diff --git a/.gitignore b/.gitignore index 88cae3c..88237ca 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ **/production/*.csv **/production/*.ipc **/production/ +*.elf +*.uf2 +.idea +.vscode diff --git a/go.mod b/go.mod index 36ad461..9fd0753 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,16 @@ -module github.com/sago35/tinygo-keyboard +module github.com/percyjw-2/tinygo-keyboard -go 1.19 +go 1.22.0 + +toolchain go1.23.1 require ( github.com/itchio/lzma v0.0.0-20190703113020-d3e24e3e3d49 - golang.org/x/exp v0.0.0-20231226003508-02704c960a9b - tinygo.org/x/drivers v0.27.0 - tinygo.org/x/tinydraw v0.3.0 - tinygo.org/x/tinyfont v0.3.0 + github.com/sago35/tinygo-keyboard v0.0.0-20240801000429-80e67ab2d444 + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 + tinygo.org/x/drivers v0.28.0 + tinygo.org/x/tinydraw v0.4.0 + tinygo.org/x/tinyfont v0.4.0 ) require github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect diff --git a/go.sum b/go.sum index dace614..6daac54 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,27 @@ github.com/bgould/http v0.0.0-20190627042742-d268792bdee7/go.mod h1:BTqvVegvwifopl4KTEDth6Zezs9eR+lCWhvGKvkxJHE= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= +github.com/frankban/quicktest v1.10.2 h1:19ARM85nVi4xH7xPXuc5eM/udya5ieh7b/Sv+d844Tk= github.com/frankban/quicktest v1.10.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/itchio/lzma v0.0.0-20190703113020-d3e24e3e3d49 h1:+YrBMf3rkLjkT10zIHyVE4S7ma4hqvfjl6XgnzZwS6o= github.com/itchio/lzma v0.0.0-20190703113020-d3e24e3e3d49/go.mod h1:avNrevQMli1pYPsz1+HIHMvx95pk6O+6otbWqCZPeZI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/sago35/tinygo-keyboard v0.0.0-20240718132338-1f0852885672 h1:mczTPYfh9yjoa6GO967sNW+6LhFjHn2TrTSwW9Wr108= +github.com/sago35/tinygo-keyboard v0.0.0-20240718132338-1f0852885672/go.mod h1:jFhDDtRipnSbvhoqlGrR2M7IInnjcMUzuSWznF6obqM= +github.com/sago35/tinygo-keyboard v0.0.0-20240801000429-80e67ab2d444 h1:upA/EBMxms0PV6Lr8Rz27nBSlAvFJkMU9q8AUceya2g= +github.com/sago35/tinygo-keyboard v0.0.0-20240801000429-80e67ab2d444/go.mod h1:jFhDDtRipnSbvhoqlGrR2M7IInnjcMUzuSWznF6obqM= github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -25,10 +35,16 @@ tinygo.org/x/drivers v0.16.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2 tinygo.org/x/drivers v0.19.0/go.mod h1:uJD/l1qWzxzLx+vcxaW0eY464N5RAgFi1zTVzASFdqI= tinygo.org/x/drivers v0.27.0 h1:TEGk1lQvEhXxfvpEhUu+pwmCnhtldPI+hpHlO9VYixI= tinygo.org/x/drivers v0.27.0/go.mod h1:q/mU8G/wz821p8xXqbkBACOlmZFDHXd//DnYnCW+dDQ= +tinygo.org/x/drivers v0.28.0 h1:ROVrGGXddmpn2+oV/Bu3LceYbtPCJckmgIqvPcN/L0k= +tinygo.org/x/drivers v0.28.0/go.mod h1:T6snsUqS0RAxOANxiV81fQwLxDDNmprxTAYzmxoA7J0= tinygo.org/x/tinydraw v0.3.0 h1:OjsdMcES5+7IIs/4diFpq/pWFsa0VKtbi1mURuj2q64= tinygo.org/x/tinydraw v0.3.0/go.mod h1:Yz0vLSP2rHsIKpLYkEmLnE+2zyhhITu2LxiVtLRiW6I= +tinygo.org/x/tinydraw v0.4.0 h1:U9V0mHz8/jPShKjlh199vCfq1ARFyUOD1b+FfqIwV8c= +tinygo.org/x/tinydraw v0.4.0/go.mod h1:WCV/EMljTv8w04iAxjv+fRD6/4ffx0afATYeJlN90Yo= tinygo.org/x/tinyfont v0.2.1/go.mod h1:eLqnYSrFRjt5STxWaMeOWJTzrKhXqpWw7nU3bPfKOAM= tinygo.org/x/tinyfont v0.3.0 h1:HIRLQoI3oc+2CMhPcfv+Ig88EcTImE/5npjqOnMD4lM= tinygo.org/x/tinyfont v0.3.0/go.mod h1:+TV5q0KpwSGRWnN+ITijsIhrWYJkoUCp9MYELjKpAXk= +tinygo.org/x/tinyfont v0.4.0 h1:XexPKEKiHInf6p4CMCJwsIheVPY0T46HUs6ictYyZfE= +tinygo.org/x/tinyfont v0.4.0/go.mod h1:7nVj3j3geqBoPDzpFukAhF1C8AP9YocMsZy0HSAcGCA= tinygo.org/x/tinyfs v0.1.0/go.mod h1:ysc8Y92iHfhTXeyEM9+c7zviUQ4fN9UCFgSOFfMWv20= tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4= diff --git a/kbmatrix.go b/kbmatrix.go index a10be33..51f69c2 100644 --- a/kbmatrix.go +++ b/kbmatrix.go @@ -54,7 +54,7 @@ func (d *Device) AddMatrixKeyboard(colPins, rowPins []machine.Pin, keys [][]Keyc options: o, callback: func(layer, index int, state State) {}, cycleCounter: cycleCnt, - debounce: 8, + debounce: 2, } d.kb = append(d.kb, k) diff --git a/keyboard.go b/keyboard.go index 133465d..922574d 100644 --- a/keyboard.go +++ b/keyboard.go @@ -24,6 +24,8 @@ type Device struct { flashCh chan bool flashCnt int + rgbMat *RGBMatrix + kb []KBer layer int @@ -84,7 +86,7 @@ func (d *Device) OverrideCtrlH() { } } -func (d *Device) Init() error { +func (d *Device) Init(ctx context.Context) error { for _, k := range d.kb { err := k.Init() if err != nil { @@ -100,7 +102,8 @@ func (d *Device) Init() error { keys := d.GetMaxKeyCount() // TODO: refactor - rbuf := make([]byte, 4+layers*keyboards*keys*2+len(device.Macros)) + rgbStorageSize := 2 + 1 + 3 // currentEffect + speed + HSV + rbuf := make([]byte, 4+layers*keyboards*keys*2+len(device.Macros)+rgbStorageSize) _, err := machine.Flash.ReadAt(rbuf, 0) if err != nil { return err @@ -123,6 +126,12 @@ func (d *Device) Init() error { } } + modeID := uint16(rbuf[offset]) | (uint16(rbuf[offset+1]) >> 8) + device.SetCurrentRGBMode(modeID) + device.SetCurrentSpeed(rbuf[offset+2]) + device.SetCurrentHSV(rbuf[offset+3], rbuf[offset+4], rbuf[offset+5]) + offset += 6 + for i, b := range rbuf[offset:] { if b == 0xFF { b = 0 @@ -131,6 +140,11 @@ func (d *Device) Init() error { } //copy(device.Macros[:], rbuf[offset:]) + // Start RGB task + go func() { + _ = d.updateRGBTask(ctx) + }() + return nil } @@ -347,7 +361,7 @@ func decKey(k uint32) (int, int, int) { } func (d *Device) Loop(ctx context.Context) error { - err := d.Init() + err := d.Init(ctx) if err != nil { return err } @@ -379,7 +393,7 @@ func (d *Device) Key(layer, kbIndex, index int) Keycode { } func (d *Device) KeyVia(layer, kbIndex, index int) Keycode { - //fmt.Printf(" KeyVia(%d, %d, %d)\n", layer, kbIndex, index) + //fmt.Printf(" KeyVia(%d, %d, %d)\n", layer, KbIndex, index) if kbIndex >= len(d.kb) { return 0 } @@ -437,7 +451,7 @@ func (d *Device) SetKeycodeVia(layer, kbIndex, index int, key Keycode) { if kbIndex >= len(d.kb) { return } - //fmt.Printf("SetKeycodeVia(%d, %d, %d, %04X)\n", layer, kbIndex, index, key) + //fmt.Printf("SetKeycodeVia(%d, %d, %d, %04X)\n", layer, KbIndex, index, key) kc := keycodeViaToTGK(key) d.kb[kbIndex].SetKeycode(layer, index, kc) diff --git a/rgb.go b/rgb.go new file mode 100644 index 0000000..cf523e7 --- /dev/null +++ b/rgb.go @@ -0,0 +1,295 @@ +//go:build tinygo + +package keyboard + +import ( + "context" + "image/color" + "time" + "tinygo.org/x/drivers/ws2812" +) + +type RGBMatrix struct { + maximumBrightness uint8 + ledCount uint16 + LedMatrixMapping []LedMatrixPosition + CenterXPhysical uint8 + CenterYPhysical uint8 + implementedEffects []RgbAnimation + currentEffect RgbAnimation + CurrentSpeed uint8 + CurrentHue uint8 + CurrentSaturation uint8 + CurrentValue uint8 + LedMatrixDirectVals []LedMatrixDirectModeColor + LedMatrixVals []color.RGBA + ledDriver *ws2812.Device +} + +type LedMatrixPosition struct { + PhysicalX uint8 + PhysicalY uint8 + KbIndex uint8 + MatrixIndex uint8 + LedFlags uint8 +} + +type LedMatrixDirectModeColor struct { + H uint8 + S uint8 + V uint8 +} + +type RgbAnimationFunc func(matrix *RGBMatrix) + +type RgbAnimation struct { + AnimationFunc RgbAnimationFunc + AnimationType uint16 +} + +const ( + // LED Flags + LED_FLAG_NONE uint8 = 0x00 // If this LED has no flags + LED_FLAG_ALL uint8 = 0xFF // if this LED has all flags + LED_FLAG_MODIFIER uint8 = 0x01 // if the Key for this LED is a modifier + LED_FLAG_UNDERGLOW uint8 = 0x02 // if the LED is for underglow + LED_FLAG_KEYLIGHT uint8 = 0x04 // if the LED is for key backlight +) + +const ( + // RGB Modes + VIALRGB_EFFECT_OFF = iota + VIALRGB_EFFECT_DIRECT + VIALRGB_EFFECT_SOLID_COLOR + VIALRGB_EFFECT_ALPHAS_MODS + VIALRGB_EFFECT_GRADIENT_UP_DOWN + VIALRGB_EFFECT_GRADIENT_LEFT_RIGHT + VIALRGB_EFFECT_BREATHING + VIALRGB_EFFECT_BAND_SAT + VIALRGB_EFFECT_BAND_VAL + VIALRGB_EFFECT_BAND_PINWHEEL_SAT + VIALRGB_EFFECT_BAND_PINWHEEL_VAL + VIALRGB_EFFECT_BAND_SPIRAL_SAT + VIALRGB_EFFECT_BAND_SPIRAL_VAL + VIALRGB_EFFECT_CYCLE_ALL + VIALRGB_EFFECT_CYCLE_LEFT_RIGHT + VIALRGB_EFFECT_CYCLE_UP_DOWN + VIALRGB_EFFECT_RAINBOW_MOVING_CHEVRON + VIALRGB_EFFECT_CYCLE_OUT_IN + VIALRGB_EFFECT_CYCLE_OUT_IN_DUAL + VIALRGB_EFFECT_CYCLE_PINWHEEL + VIALRGB_EFFECT_CYCLE_SPIRAL + VIALRGB_EFFECT_DUAL_BEACON + VIALRGB_EFFECT_RAINBOW_BEACON + VIALRGB_EFFECT_RAINBOW_PINWHEELS + VIALRGB_EFFECT_RAINDROPS + VIALRGB_EFFECT_JELLYBEAN_RAINDROPS + VIALRGB_EFFECT_HUE_BREATHING + VIALRGB_EFFECT_HUE_PENDULUM + VIALRGB_EFFECT_HUE_WAVE + VIALRGB_EFFECT_TYPING_HEATMAP + VIALRGB_EFFECT_DIGITAL_RAIN + VIALRGB_EFFECT_SOLID_REACTIVE_SIMPLE + VIALRGB_EFFECT_SOLID_REACTIVE + VIALRGB_EFFECT_SOLID_REACTIVE_WIDE + VIALRGB_EFFECT_SOLID_REACTIVE_MULTIWIDE + VIALRGB_EFFECT_SOLID_REACTIVE_CROSS + VIALRGB_EFFECT_SOLID_REACTIVE_MULTICROSS + VIALRGB_EFFECT_SOLID_REACTIVE_NEXUS + VIALRGB_EFFECT_SOLID_REACTIVE_MULTINEXUS + VIALRGB_EFFECT_SPLASH + VIALRGB_EFFECT_MULTISPLASH + VIALRGB_EFFECT_SOLID_SPLASH + VIALRGB_EFFECT_SOLID_MULTISPLASH + VIALRGB_EFFECT_PIXEL_RAIN + VIALRGB_EFFECT_PIXEL_FRACTAL +) + +func (d *Device) AddRGBMatrix(brightness uint8, ledCount uint16, ledMatrixMapping []LedMatrixPosition, animations []RgbAnimation, ledDriver *ws2812.Device) { + if int(ledCount) != len(ledMatrixMapping) { + panic("LedMatrixMapping must have length equal to number of LedMatrixMapping") + } + effectOffAnimation := RgbAnimation{ + AnimationFunc: func(matrix *RGBMatrix) { + matrix.ledDriver.WriteColors(matrix.LedMatrixVals) + }, + AnimationType: VIALRGB_EFFECT_OFF, + } + + maxX := uint8(0) + maxY := uint8(0) + for _, position := range ledMatrixMapping { + if maxX < position.PhysicalX { + maxX = position.PhysicalX + } + if maxY < position.PhysicalY { + maxY = position.PhysicalY + } + } + + rgbMatrix := RGBMatrix{ + maximumBrightness: brightness, + ledCount: ledCount, + LedMatrixMapping: ledMatrixMapping, + CenterXPhysical: maxX / 2, + CenterYPhysical: maxY / 2, + implementedEffects: []RgbAnimation{ + effectOffAnimation, + }, + currentEffect: effectOffAnimation, + CurrentSpeed: 0x00, + CurrentHue: 0xFF, + CurrentSaturation: 0xFF, + CurrentValue: brightness, + LedMatrixVals: make([]color.RGBA, ledCount), + ledDriver: ledDriver, + } + rgbMatrix.implementedEffects = append(rgbMatrix.implementedEffects, animations...) + for _, animation := range animations { + if animation.AnimationType == VIALRGB_EFFECT_DIRECT { + rgbMatrix.LedMatrixDirectVals = make([]LedMatrixDirectModeColor, ledCount) + } + } + d.rgbMat = &rgbMatrix +} + +func (d *Device) GetRGBMatrixMaximumBrightness() uint8 { + if !d.IsRGBMatrixEnabled() { + return 0 + } + return d.rgbMat.maximumBrightness +} + +func (d *Device) GetRGBMatrixLEDCount() uint16 { + if !d.IsRGBMatrixEnabled() { + return 0 + } + return d.rgbMat.ledCount +} + +func (d *Device) GetRGBMatrixLEDMapping(ledIndex uint16) LedMatrixPosition { + invalidPosition := LedMatrixPosition{ + KbIndex: 0xFF, + MatrixIndex: 0xFF, + } + if !d.IsRGBMatrixEnabled() || ledIndex >= d.rgbMat.ledCount { + return invalidPosition + } + return d.rgbMat.LedMatrixMapping[ledIndex] +} + +func (d *Device) GetSupportedRGBModes() []RgbAnimation { + if !d.IsRGBMatrixEnabled() { + return []RgbAnimation{} + } + return d.rgbMat.implementedEffects +} + +func (d *Device) GetCurrentRGBMode() uint16 { + if !d.IsRGBMatrixEnabled() { + return 0 + } + return d.rgbMat.currentEffect.AnimationType +} + +func (d *Device) SetCurrentRGBMode(mode uint16) { + if !d.IsRGBMatrixEnabled() { + return + } + for _, e := range d.rgbMat.implementedEffects { + if e.AnimationType == mode { + d.rgbMat.currentEffect = e + } + } +} + +func (d *Device) GetCurrentSpeed() uint8 { + if !d.IsRGBMatrixEnabled() { + return 0 + } + return d.rgbMat.CurrentSpeed +} + +func (d *Device) SetCurrentSpeed(speed uint8) { + if !d.IsRGBMatrixEnabled() { + return + } + d.rgbMat.CurrentSpeed = speed +} + +func (d *Device) GetCurrentHue() uint8 { + if !d.IsRGBMatrixEnabled() { + return 0 + } + return d.rgbMat.CurrentHue +} + +func (d *Device) GetCurrentSaturation() uint8 { + if !d.IsRGBMatrixEnabled() { + return 0 + } + return d.rgbMat.CurrentSaturation +} + +func (d *Device) GetCurrentValue() uint8 { + if !d.IsRGBMatrixEnabled() { + return 0 + } + return d.rgbMat.CurrentValue +} + +func (d *Device) SetCurrentHSV(hue uint8, saturation uint8, value uint8) { + if !d.IsRGBMatrixEnabled() { + return + } + d.rgbMat.CurrentHue = hue + d.rgbMat.CurrentSaturation = saturation + d.rgbMat.CurrentValue = value +} + +func (d *Device) SetDirectHSV(hue uint8, saturation uint8, value uint8, ledIndex uint16) { + if !d.IsDirectModeEnabled() { + return + } + rgb := d.rgbMat + var actualValue uint8 + if value > rgb.maximumBrightness { + actualValue = rgb.maximumBrightness + } else { + actualValue = value + } + rgb.LedMatrixDirectVals[ledIndex] = LedMatrixDirectModeColor{ + H: hue, + S: saturation, + V: actualValue, + } +} + +func (d *Device) updateRGBTask(ctx context.Context) error { + if !d.IsRGBMatrixEnabled() { + return nil + } + rgb := d.rgbMat + ticker := time.Tick(10 * time.Millisecond) + cont := true + for cont { + select { + case <-ctx.Done(): + cont = false + continue + case <-ticker: + default: + } + rgb.currentEffect.AnimationFunc(rgb) + _ = rgb.ledDriver.WriteColors(rgb.LedMatrixVals) + } + return nil +} + +func (d *Device) IsRGBMatrixEnabled() bool { + return d.rgbMat != nil +} + +func (d *Device) IsDirectModeEnabled() bool { + return d.IsRGBMatrixEnabled() && d.rgbMat.LedMatrixDirectVals != nil +} diff --git a/rgbanimations/utilFuncsMath.go b/rgbanimations/utilFuncsMath.go new file mode 100644 index 0000000..203b702 --- /dev/null +++ b/rgbanimations/utilFuncsMath.go @@ -0,0 +1,148 @@ +package rgbanimations + +// Source: https://stackoverflow.com/a/14733008 + +func HSVToRGB(h, s, v uint8) (r, g, b, a uint8) { + if s == 0 { + return v, v, v, v + } + region := h / 43 + remainder := (h - (region * 43)) * 6 + + var s16, v16 uint16 + s16 = uint16(s) + v16 = uint16(v) + + p := uint8((v16 * (255 - s16)) >> 8) + q := uint8((v16 * (255 - ((s16 * uint16(remainder)) >> 8))) >> 8) + t := uint8((v16 * (255 - ((s16 * uint16(255-remainder)) >> 8))) >> 8) + + switch region { + case 0: + return v, t, p, v + case 1: + return q, v, p, v + case 2: + return p, v, t, v + case 3: + return p, q, v, v + case 4: + return t, p, v, v + default: + return v, p, q, v + } +} + +// Math Functions based on lib8tion math8.h + +func Scale8(i uint8, scale uint8) uint8 { + return uint8((uint16(i) * uint16(scale)) >> 8) +} + +func Scale16by8(i uint16, scale uint8) uint16 { + return (i * (1 + uint16(scale))) >> 8 +} + +func Abs8(i int8) uint8 { + if i < 0 { + return uint8(-i) + } + return uint8(i) +} + +func Abs16(i int16) int16 { + if i < 0 { + return int16(-i) + } + return int16(i) +} + +func Sin8(theta uint8) uint8 { + offset := theta + if theta&0x40 != 0 { + offset = 0xFF - offset + } + offset &= 0x3F + + secoffset := offset & 0x0F + if theta&0x40 != 0 { + secoffset++ + } + + section := offset >> 4 + s2 := section * 2 + var p = []uint8{0, 49, 49, 41, 90, 27, 117, 10} + b := p[s2] + m16 := p[s2+1] + + mx := (m16 * secoffset) >> 4 + + y := int8(mx + b) + if theta&0x80 != 0 { + y = -y + } + + y += 127 + y++ + + return uint8(y) +} + +func Cos8(theta uint8) uint8 { + return Sin8(theta + 64) +} + +func Atan28(dy int16, dx int16) uint8 { + if dy == 0 { + if dx >= 0 { + return 0 + } else { + return 128 + } + } + + var absY int16 + if dy < 0 { + absY = -dy + } else { + absY = dy + } + var a int8 + if dx >= 0 { + a = int8(32 - (32 * (dx - absY) / (dx + absY))) + } else { + a = int8(96 - (32 * (dx + absY) / (dx - absY))) + } + if dy < 0 { + return uint8(-a) + } + return uint8(a) +} + +func Sqrt16(x uint16) uint8 { + if x <= 1 { + return uint8(x) + } + + low := uint8(1) // lower bound + var hi, mid uint8 + + if x > 7904 { + hi = 255 + } else { + hi = uint8((x >> 5) + 5) // initial estimate for upper bound + } + + for ok := true; ok; ok = hi >= mid { // emulation of do-while loop + mid = (low + hi) >> 1 + if uint16(mid)*uint16(mid) > x { + hi = mid - 1 + } else { + if mid == 255 { + return 255 + } + low = mid + 1 + } + } + return low - 1 +} diff --git a/rgbanimations/utilFuncsRunners.go b/rgbanimations/utilFuncsRunners.go new file mode 100644 index 0000000..24c66ee --- /dev/null +++ b/rgbanimations/utilFuncsRunners.go @@ -0,0 +1,53 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +var time = uint16(0) + +type effectRunnerIFunc func(matrix *keyboard.RGBMatrix, i int, time uint16) (uint8, uint8, uint8) +type effectRunnerDXDYFunc func(matrix *keyboard.RGBMatrix, dx int16, dy int16, time uint16) (uint8, uint8, uint8) +type effectRunnerDXDYDistFunc func(matrix *keyboard.RGBMatrix, dx int16, dy int16, dist uint8, time uint16) (uint8, uint8, uint8) +type effectRunnerSinCosIFunc func(matrix *keyboard.RGBMatrix, sin int8, cos int8, i int, time uint16) (uint8, uint8, uint8) + +func effectRunnerI(matrix *keyboard.RGBMatrix, mathFunc effectRunnerIFunc) { + timeScaled := Scale16by8(time, matrix.CurrentSpeed) + for i, val := range matrix.LedMatrixVals { + h, s, v := mathFunc(matrix, i, timeScaled) + val.R, val.G, val.B, val.A = HSVToRGB(h, s, v) + } + time++ +} + +func effectRunnerDXDY(matrix *keyboard.RGBMatrix, mathFunc effectRunnerDXDYFunc) { + timeScaled := Scale16by8(time, matrix.CurrentSpeed) + for i, val := range matrix.LedMatrixVals { + dx := int16(matrix.LedMatrixMapping[i].PhysicalX) - int16(matrix.CenterXPhysical) + dy := int16(matrix.LedMatrixMapping[i].PhysicalY) - int16(matrix.CenterYPhysical) + h, s, v := mathFunc(matrix, dx, dy, timeScaled) + val.R, val.G, val.B, val.A = HSVToRGB(h, s, v) + } + time++ +} + +func effectRunnerDXDYDist(matrix *keyboard.RGBMatrix, mathFunc effectRunnerDXDYDistFunc) { + timeScaled := Scale16by8(time, matrix.CurrentSpeed) + for i, val := range matrix.LedMatrixVals { + dx := int16(matrix.LedMatrixMapping[i].PhysicalX) - int16(matrix.CenterXPhysical) + dy := int16(matrix.LedMatrixMapping[i].PhysicalY) - int16(matrix.CenterYPhysical) + dist := Sqrt16(uint16(dx*dx + dy*dy)) + h, s, v := mathFunc(matrix, dx, dy, dist, timeScaled) + val.R, val.G, val.B, val.A = HSVToRGB(h, s, v) + } + time++ +} + +func effectRunnerSinCosI(matrix *keyboard.RGBMatrix, mathFunc effectRunnerSinCosIFunc) { + timeScaled := Scale16by8(time, matrix.CurrentSpeed) + cosValue := int8(Cos8(uint8(time)) - 128) + sinValue := int8(Sin8(uint8(time)) - 128) + for i, val := range matrix.LedMatrixVals { + h, s, v := mathFunc(matrix, sinValue, cosValue, i, timeScaled) + val.R, val.G, val.B, val.A = HSVToRGB(h, s, v) + } + time++ +} diff --git a/rgbanimations/vialrgbAlphasMods.go b/rgbanimations/vialrgbAlphasMods.go new file mode 100644 index 0000000..327117c --- /dev/null +++ b/rgbanimations/vialrgbAlphasMods.go @@ -0,0 +1,28 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetAlphasModsAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBAlphasModsAnim, + AnimationType: keyboard.VIALRGB_EFFECT_ALPHAS_MODS, + } +} + +func vialRGBAlphasModsAnim(matrix *keyboard.RGBMatrix) { + r1, g1, b1, a1 := HSVToRGB(matrix.CurrentHue, matrix.CurrentSaturation, matrix.CurrentValue) + r2, g2, b2, a2 := HSVToRGB((matrix.CurrentHue+matrix.CurrentSpeed)%0xFF, matrix.CurrentSaturation, matrix.CurrentValue) + for i := range matrix.LedMatrixVals { + if matrix.LedMatrixMapping[i].LedFlags&keyboard.LED_FLAG_MODIFIER == keyboard.LED_FLAG_MODIFIER { + matrix.LedMatrixVals[i].R = r2 + matrix.LedMatrixVals[i].G = g2 + matrix.LedMatrixVals[i].B = b2 + matrix.LedMatrixVals[i].A = a2 + } else { + matrix.LedMatrixVals[i].R = r1 + matrix.LedMatrixVals[i].G = g1 + matrix.LedMatrixVals[i].B = b1 + matrix.LedMatrixVals[i].A = a1 + } + } +} diff --git a/rgbanimations/vialrgbBandPinwheelSat.go b/rgbanimations/vialrgbBandPinwheelSat.go new file mode 100644 index 0000000..d15b35d --- /dev/null +++ b/rgbanimations/vialrgbBandPinwheelSat.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetBandPinwheelSatAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBBandPinwheelSat, + AnimationType: keyboard.VIALRGB_EFFECT_BAND_PINWHEEL_SAT, + } +} + +func bandPinwheelSatMath(matrix *keyboard.RGBMatrix, dx int16, dy int16, time uint16) (uint8, uint8, uint8) { + s := Scale8(matrix.CurrentSaturation-uint8(time)-Atan28(dy, dx), matrix.CurrentSaturation) + return matrix.CurrentHue, s, matrix.CurrentValue +} + +func vialRGBBandPinwheelSat(matrix *keyboard.RGBMatrix) { + effectRunnerDXDY(matrix, bandPinwheelSatMath) +} diff --git a/rgbanimations/vialrgbBandPinwheelVal.go b/rgbanimations/vialrgbBandPinwheelVal.go new file mode 100644 index 0000000..c84d355 --- /dev/null +++ b/rgbanimations/vialrgbBandPinwheelVal.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetBandPinwheelValAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBBandPinwheelVal, + AnimationType: keyboard.VIALRGB_EFFECT_BAND_PINWHEEL_VAL, + } +} + +func bandPinwheelValMath(matrix *keyboard.RGBMatrix, dx int16, dy int16, time uint16) (uint8, uint8, uint8) { + v := Scale8(matrix.CurrentValue-uint8(time)-Atan28(dy, dx), matrix.CurrentValue) + return matrix.CurrentHue, matrix.CurrentSaturation, v +} + +func vialRGBBandPinwheelVal(matrix *keyboard.RGBMatrix) { + effectRunnerDXDY(matrix, bandPinwheelValMath) +} diff --git a/rgbanimations/vialrgbBandSat.go b/rgbanimations/vialrgbBandSat.go new file mode 100644 index 0000000..a5dc64f --- /dev/null +++ b/rgbanimations/vialrgbBandSat.go @@ -0,0 +1,26 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetBandSatAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBBandSat, + AnimationType: keyboard.VIALRGB_EFFECT_BAND_SAT, + } +} + +func bandSatMath(matrix *keyboard.RGBMatrix, i int, time uint16) (uint8, uint8, uint8) { + s16 := int16(matrix.CurrentSaturation) - + Abs16(int16(Scale8(matrix.LedMatrixMapping[i].PhysicalX, 228))+28-int16(time))*8 + var s8 uint8 + if s16 < 0 { + s8 = 0 + } else { + s8 = Scale8(uint8(s16), matrix.CurrentSaturation) + } + return matrix.CurrentHue, s8, matrix.CurrentValue +} + +func vialRGBBandSat(matrix *keyboard.RGBMatrix) { + effectRunnerI(matrix, bandSatMath) +} diff --git a/rgbanimations/vialrgbBandSpiralSat.go b/rgbanimations/vialrgbBandSpiralSat.go new file mode 100644 index 0000000..f33993d --- /dev/null +++ b/rgbanimations/vialrgbBandSpiralSat.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetBansSpiralSatAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBBandSpiralSat, + AnimationType: keyboard.VIALRGB_EFFECT_BAND_SPIRAL_SAT, + } +} + +func bandSpiralSatMath(matrix *keyboard.RGBMatrix, dx int16, dy int16, dist uint8, time uint16) (uint8, uint8, uint8) { + s := Scale8(matrix.CurrentSaturation+dist-uint8(time)-Atan28(dy, dx), matrix.CurrentSaturation) + return matrix.CurrentHue, s, matrix.CurrentValue +} + +func vialRGBBandSpiralSat(matrix *keyboard.RGBMatrix) { + effectRunnerDXDYDist(matrix, bandSpiralSatMath) +} diff --git a/rgbanimations/vialrgbBandSpiralVal.go b/rgbanimations/vialrgbBandSpiralVal.go new file mode 100644 index 0000000..63d06e3 --- /dev/null +++ b/rgbanimations/vialrgbBandSpiralVal.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetBansSpiralValAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBBandSpiralVal, + AnimationType: keyboard.VIALRGB_EFFECT_BAND_SPIRAL_VAL, + } +} + +func bandSpiralValMath(matrix *keyboard.RGBMatrix, dx int16, dy int16, dist uint8, time uint16) (uint8, uint8, uint8) { + v := Scale8(matrix.CurrentValue+dist-uint8(time)-Atan28(dy, dx), matrix.CurrentValue) + return matrix.CurrentHue, matrix.CurrentSaturation, v +} + +func vialRGBBandSpiralVal(matrix *keyboard.RGBMatrix) { + effectRunnerDXDYDist(matrix, bandSpiralValMath) +} diff --git a/rgbanimations/vialrgbBandVal.go b/rgbanimations/vialrgbBandVal.go new file mode 100644 index 0000000..7dedc01 --- /dev/null +++ b/rgbanimations/vialrgbBandVal.go @@ -0,0 +1,26 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetBandValAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBBandVal, + AnimationType: keyboard.VIALRGB_EFFECT_BAND_VAL, + } +} + +func bandValMath(matrix *keyboard.RGBMatrix, i int, time uint16) (uint8, uint8, uint8) { + v16 := int16(matrix.CurrentValue) - + Abs16(int16(Scale8(matrix.LedMatrixMapping[i].PhysicalX, 228))+28-int16(time))*8 + var v8 uint8 + if v16 < 0 { + v8 = 0 + } else { + v8 = Scale8(uint8(v16), matrix.CurrentValue) + } + return matrix.CurrentHue, matrix.CurrentSaturation, v8 +} + +func vialRGBBandVal(matrix *keyboard.RGBMatrix) { + effectRunnerI(matrix, bandValMath) +} diff --git a/rgbanimations/vialrgbBreathing.go b/rgbanimations/vialrgbBreathing.go new file mode 100644 index 0000000..b929f26 --- /dev/null +++ b/rgbanimations/vialrgbBreathing.go @@ -0,0 +1,23 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetBreathingAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBBreathing, + AnimationType: keyboard.VIALRGB_EFFECT_BREATHING, + } +} + +func vialRGBBreathing(matrix *keyboard.RGBMatrix) { + timeScaled := Scale16by8(time, matrix.CurrentSpeed) + v := Scale8(Abs8(int8(Sin8(uint8(timeScaled))-128))*8, matrix.CurrentValue) + r, g, b, a := HSVToRGB(matrix.CurrentHue, matrix.CurrentSaturation, v) + for _, val := range matrix.LedMatrixVals { + val.R = r + val.G = g + val.B = b + val.A = a + } + time++ +} diff --git a/rgbanimations/vialrgbCycleAll.go b/rgbanimations/vialrgbCycleAll.go new file mode 100644 index 0000000..f5cce2b --- /dev/null +++ b/rgbanimations/vialrgbCycleAll.go @@ -0,0 +1,18 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetCycleAllAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBCycleAll, + AnimationType: keyboard.VIALRGB_EFFECT_CYCLE_ALL, + } +} + +func cycleAllMath(matrix *keyboard.RGBMatrix, i int, time uint16) (uint8, uint8, uint8) { + return uint8(time), matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBCycleAll(matrix *keyboard.RGBMatrix) { + effectRunnerI(matrix, cycleAllMath) +} diff --git a/rgbanimations/vialrgbCycleLeftRight.go b/rgbanimations/vialrgbCycleLeftRight.go new file mode 100644 index 0000000..05359e5 --- /dev/null +++ b/rgbanimations/vialrgbCycleLeftRight.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetCycleLeftRightAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBCycleLeftRight, + AnimationType: keyboard.VIALRGB_EFFECT_CYCLE_LEFT_RIGHT, + } +} + +func cycleLeftRightMath(matrix *keyboard.RGBMatrix, i int, time uint16) (uint8, uint8, uint8) { + h := matrix.LedMatrixMapping[i].PhysicalX - uint8(time) + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBCycleLeftRight(matrix *keyboard.RGBMatrix) { + effectRunnerI(matrix, cycleLeftRightMath) +} diff --git a/rgbanimations/vialrgbCycleOutIn.go b/rgbanimations/vialrgbCycleOutIn.go new file mode 100644 index 0000000..e52bf3e --- /dev/null +++ b/rgbanimations/vialrgbCycleOutIn.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetCycleOutInAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBCycleOutIn, + AnimationType: keyboard.VIALRGB_EFFECT_CYCLE_OUT_IN, + } +} + +func cycleOutInMath(matrix *keyboard.RGBMatrix, _ int16, _ int16, dist uint8, time uint16) (uint8, uint8, uint8) { + h := 3*dist/2 + uint8(time) + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBCycleOutIn(matrix *keyboard.RGBMatrix) { + effectRunnerDXDYDist(matrix, cycleOutInMath) +} diff --git a/rgbanimations/vialrgbCycleOutInDual.go b/rgbanimations/vialrgbCycleOutInDual.go new file mode 100644 index 0000000..63be74d --- /dev/null +++ b/rgbanimations/vialrgbCycleOutInDual.go @@ -0,0 +1,21 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetCycleOutInDualAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBCycleOutInDual, + AnimationType: keyboard.VIALRGB_EFFECT_CYCLE_OUT_IN_DUAL, + } +} + +func cycleOutInDualMath(matrix *keyboard.RGBMatrix, dx int16, dy int16, time uint16) (uint8, uint8, uint8) { + dx = int16(matrix.CenterXPhysical/2) - Abs16(dx) + dist := Sqrt16(uint16(dx*dx) + uint16(dy*dy)) + h := 3*dist + uint8(time) + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBCycleOutInDual(matrix *keyboard.RGBMatrix) { + effectRunnerDXDY(matrix, cycleOutInDualMath) +} diff --git a/rgbanimations/vialrgbCyclePinwheel.go b/rgbanimations/vialrgbCyclePinwheel.go new file mode 100644 index 0000000..f46f4f4 --- /dev/null +++ b/rgbanimations/vialrgbCyclePinwheel.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetCyclePinwheelAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBCyclePinwheel, + AnimationType: keyboard.VIALRGB_EFFECT_CYCLE_PINWHEEL, + } +} + +func cyclePinwheelMath(matrix *keyboard.RGBMatrix, dx int16, dy int16, time uint16) (uint8, uint8, uint8) { + h := Atan28(dy, dx) + uint8(time) + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBCyclePinwheel(matrix *keyboard.RGBMatrix) { + effectRunnerDXDY(matrix, cyclePinwheelMath) +} diff --git a/rgbanimations/vialrgbCycleSpiral.go b/rgbanimations/vialrgbCycleSpiral.go new file mode 100644 index 0000000..3fd0294 --- /dev/null +++ b/rgbanimations/vialrgbCycleSpiral.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetCycleSpiralAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBCycleSpiral, + AnimationType: keyboard.VIALRGB_EFFECT_CYCLE_SPIRAL, + } +} + +func cycleSpiralMath(matrix *keyboard.RGBMatrix, dx int16, dy int16, dist uint8, time uint16) (uint8, uint8, uint8) { + h := dist - uint8(time) - Atan28(dy, dx) + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBCycleSpiral(matrix *keyboard.RGBMatrix) { + effectRunnerDXDYDist(matrix, cycleSpiralMath) +} diff --git a/rgbanimations/vialrgbCycleUpDown.go b/rgbanimations/vialrgbCycleUpDown.go new file mode 100644 index 0000000..7bf24de --- /dev/null +++ b/rgbanimations/vialrgbCycleUpDown.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetCycleUpDownAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBCycleUpDown, + AnimationType: keyboard.VIALRGB_EFFECT_CYCLE_UP_DOWN, + } +} + +func cycleUpDownMath(matrix *keyboard.RGBMatrix, i int, time uint16) (uint8, uint8, uint8) { + h := matrix.LedMatrixMapping[i].PhysicalY - uint8(time) + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBCycleUpDown(matrix *keyboard.RGBMatrix) { + effectRunnerI(matrix, cycleUpDownMath) +} diff --git a/rgbanimations/vialrgbDirect.go b/rgbanimations/vialrgbDirect.go new file mode 100644 index 0000000..d80b23c --- /dev/null +++ b/rgbanimations/vialrgbDirect.go @@ -0,0 +1,20 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetDirectAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBDirectAnim, + AnimationType: keyboard.VIALRGB_EFFECT_DIRECT, + } +} + +func vialRGBDirectAnim(matrix *keyboard.RGBMatrix) { + for i, hsv := range matrix.LedMatrixDirectVals { + r, g, b, a := HSVToRGB(hsv.H, hsv.S, hsv.V) + matrix.LedMatrixVals[i].R = r + matrix.LedMatrixVals[i].G = g + matrix.LedMatrixVals[i].B = b + matrix.LedMatrixVals[i].A = a + } +} diff --git a/rgbanimations/vialrgbDualBeacon.go b/rgbanimations/vialrgbDualBeacon.go new file mode 100644 index 0000000..b9c3b3a --- /dev/null +++ b/rgbanimations/vialrgbDualBeacon.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetDualBeaconAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBDualBeacon, + AnimationType: keyboard.VIALRGB_EFFECT_DUAL_BEACON, + } +} + +func dualBeaconMath(matrix *keyboard.RGBMatrix, sin int8, cos int8, i int, _ uint16) (uint8, uint8, uint8) { + h := matrix.CurrentHue + uint8(int8(matrix.LedMatrixMapping[i].PhysicalY-matrix.CenterYPhysical)*cos+int8(matrix.LedMatrixMapping[i].PhysicalX-matrix.CenterXPhysical)*sin)/128 + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBDualBeacon(matrix *keyboard.RGBMatrix) { + effectRunnerSinCosI(matrix, dualBeaconMath) +} diff --git a/rgbanimations/vialrgbGradientLeftRight.go b/rgbanimations/vialrgbGradientLeftRight.go new file mode 100644 index 0000000..00a08b7 --- /dev/null +++ b/rgbanimations/vialrgbGradientLeftRight.go @@ -0,0 +1,22 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetGradientLeftRight() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBGradientLeftRight, + AnimationType: keyboard.VIALRGB_EFFECT_GRADIENT_LEFT_RIGHT, + } +} + +func vialRGBGradientLeftRight(matrix *keyboard.RGBMatrix) { + scale := Scale8(64, matrix.CurrentSpeed) + for i, position := range matrix.LedMatrixMapping { + h := uint16(matrix.CurrentHue) + uint16(scale*position.PhysicalX>>5) + r, g, b, a := HSVToRGB(uint8(h&0xFF), matrix.CurrentSaturation, matrix.CurrentValue) + matrix.LedMatrixVals[i].R = r + matrix.LedMatrixVals[i].G = g + matrix.LedMatrixVals[i].B = b + matrix.LedMatrixVals[i].A = a + } +} diff --git a/rgbanimations/vialrgbGradientUpDown.go b/rgbanimations/vialrgbGradientUpDown.go new file mode 100644 index 0000000..eb55fa7 --- /dev/null +++ b/rgbanimations/vialrgbGradientUpDown.go @@ -0,0 +1,22 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetGradientUpDownAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBGradientUpDown, + AnimationType: keyboard.VIALRGB_EFFECT_GRADIENT_UP_DOWN, + } +} + +func vialRGBGradientUpDown(matrix *keyboard.RGBMatrix) { + scale := Scale8(64, matrix.CurrentSpeed) + for i, position := range matrix.LedMatrixMapping { + h := uint16(matrix.CurrentHue) + uint16(scale*(position.PhysicalY>>4)) + r, g, b, a := HSVToRGB(uint8(h&0xFF), matrix.CurrentSaturation, matrix.CurrentValue) + matrix.LedMatrixVals[i].R = r + matrix.LedMatrixVals[i].G = g + matrix.LedMatrixVals[i].B = b + matrix.LedMatrixVals[i].A = a + } +} diff --git a/rgbanimations/vialrgbHueBreathing.go b/rgbanimations/vialrgbHueBreathing.go new file mode 100644 index 0000000..f28e0fb --- /dev/null +++ b/rgbanimations/vialrgbHueBreathing.go @@ -0,0 +1,25 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetHueBreathingAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBHueBreathing, + AnimationType: keyboard.VIALRGB_EFFECT_HUE_BREATHING, + } +} + +func vialRGBHueBreathing(matrix *keyboard.RGBMatrix) { + huedelta := uint8(12) + h, s, v := matrix.CurrentHue, matrix.CurrentSaturation, matrix.CurrentValue + timeScaled := Scale16by8(time, matrix.CurrentSpeed/8) + h = h + Scale8(Abs8(int8(Sin8(uint8(timeScaled)))-127)*2, huedelta) + r, g, b, a := HSVToRGB(h, s, v) + for _, val := range matrix.LedMatrixVals { + val.R = r + val.G = g + val.B = b + val.A = a + } + time++ +} diff --git a/rgbanimations/vialrgbHuePendulum.go b/rgbanimations/vialrgbHuePendulum.go new file mode 100644 index 0000000..4525243 --- /dev/null +++ b/rgbanimations/vialrgbHuePendulum.go @@ -0,0 +1,20 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetHuePendulumAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBHuePendulum, + AnimationType: keyboard.VIALRGB_EFFECT_HUE_PENDULUM, + } +} + +func huePendulumMath(matrix *keyboard.RGBMatrix, i int, time uint16) (uint8, uint8, uint8) { + huedelta := uint8(12) + h := matrix.CurrentHue + Scale8(Abs8(int8(Sin8(uint8(time))+(matrix.LedMatrixMapping[i].PhysicalX)-128))*2, huedelta) + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBHuePendulum(matrix *keyboard.RGBMatrix) { + effectRunnerI(matrix, huePendulumMath) +} diff --git a/rgbanimations/vialrgbHueWave.go b/rgbanimations/vialrgbHueWave.go new file mode 100644 index 0000000..3608ad9 --- /dev/null +++ b/rgbanimations/vialrgbHueWave.go @@ -0,0 +1,20 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetHueWave() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBHueWave, + AnimationType: keyboard.VIALRGB_EFFECT_HUE_WAVE, + } +} + +func hueWaveMath(matrix *keyboard.RGBMatrix, i int, time uint16) (uint8, uint8, uint8) { + huedelta := uint8(24) + h := matrix.CurrentHue + Scale8(Abs8(int8(matrix.LedMatrixMapping[i].PhysicalX-uint8(time))), huedelta) + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBHueWave(matrix *keyboard.RGBMatrix) { + effectRunnerI(matrix, hueWaveMath) +} diff --git a/rgbanimations/vialrgbRainbowBeacon.go b/rgbanimations/vialrgbRainbowBeacon.go new file mode 100644 index 0000000..7e71478 --- /dev/null +++ b/rgbanimations/vialrgbRainbowBeacon.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetRainbowBeaconAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBRainbowBeacon, + AnimationType: keyboard.VIALRGB_EFFECT_RAINBOW_BEACON, + } +} + +func rainbowBeaconMath(matrix *keyboard.RGBMatrix, sin int8, cos int8, i int, _ uint16) (uint8, uint8, uint8) { + h := matrix.CurrentHue + uint8(int8(matrix.LedMatrixMapping[i].PhysicalY-matrix.CenterYPhysical)*2*cos+int8(matrix.LedMatrixMapping[i].PhysicalX-matrix.CenterXPhysical)*2*sin)/128 + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBRainbowBeacon(matrix *keyboard.RGBMatrix) { + effectRunnerSinCosI(matrix, rainbowBeaconMath) +} diff --git a/rgbanimations/vialrgbRainbowMovingChevron.go b/rgbanimations/vialrgbRainbowMovingChevron.go new file mode 100644 index 0000000..2845737 --- /dev/null +++ b/rgbanimations/vialrgbRainbowMovingChevron.go @@ -0,0 +1,19 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetRainbowMovingChevronAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBRainbowMovingChevron, + AnimationType: keyboard.VIALRGB_EFFECT_RAINBOW_MOVING_CHEVRON, + } +} + +func rainbowMovingChevronMath(matrix *keyboard.RGBMatrix, i int, time uint16) (uint8, uint8, uint8) { + h := matrix.CurrentHue + Abs8(int8(matrix.LedMatrixMapping[i].PhysicalY-matrix.CenterYPhysical)+int8(matrix.CenterXPhysical-uint8(time))) + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBRainbowMovingChevron(matrix *keyboard.RGBMatrix) { + effectRunnerI(matrix, rainbowMovingChevronMath) +} diff --git a/rgbanimations/vialrgbRainbowPinwheels.go b/rgbanimations/vialrgbRainbowPinwheels.go new file mode 100644 index 0000000..9163626 --- /dev/null +++ b/rgbanimations/vialrgbRainbowPinwheels.go @@ -0,0 +1,23 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetRainbowPinwheelsAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialRGBRainbowPinwheels, + AnimationType: keyboard.VIALRGB_EFFECT_RAINBOW_PINWHEELS, + } +} + +func rainbowPinwheelsMath(matrix *keyboard.RGBMatrix, sin int8, cos int8, i int, time uint16) (uint8, uint8, uint8) { + h := matrix.CurrentHue + + uint8( + int8(matrix.LedMatrixMapping[i].PhysicalY-matrix.CenterYPhysical)*3*cos+ + int8(56-Abs8(int8(matrix.LedMatrixMapping[i].PhysicalX-matrix.CenterXPhysical)))*2*sin, + )/128 + return h, matrix.CurrentSaturation, matrix.CurrentValue +} + +func vialRGBRainbowPinwheels(matrix *keyboard.RGBMatrix) { + effectRunnerSinCosI(matrix, rainbowPinwheelsMath) +} diff --git a/rgbanimations/vialrgbSolidColor.go b/rgbanimations/vialrgbSolidColor.go new file mode 100644 index 0000000..7ef4e59 --- /dev/null +++ b/rgbanimations/vialrgbSolidColor.go @@ -0,0 +1,20 @@ +package rgbanimations + +import keyboard "github.com/percyjw-2/tinygo-keyboard" + +func GetSolidColorAnim() keyboard.RgbAnimation { + return keyboard.RgbAnimation{ + AnimationFunc: vialrgbSolidColorAnim, + AnimationType: keyboard.VIALRGB_EFFECT_SOLID_COLOR, + } +} + +func vialrgbSolidColorAnim(matrix *keyboard.RGBMatrix) { + r, g, b, a := HSVToRGB(matrix.CurrentHue, matrix.CurrentSaturation, matrix.CurrentValue) + for i := range matrix.LedMatrixVals { + matrix.LedMatrixVals[i].R = r + matrix.LedMatrixVals[i].G = g + matrix.LedMatrixVals[i].B = b + matrix.LedMatrixVals[i].A = a + } +} diff --git a/via.go b/via.go index 85ffbdc..83f699b 100644 --- a/via.go +++ b/via.go @@ -121,12 +121,6 @@ func rxHandler(b []byte) { } func rxHandler2(b []byte) bool { - switch b[0] { - //case 0x12, 0x0E: - default: - //fmt.Printf("RxHandler % X\n", b) - } - copy(txb[:32], b) switch b[0] { case 0x01: @@ -195,10 +189,107 @@ func rxHandler2(b []byte) bool { device.SetKeycodeVia(int(b[1]), int(b[2]), int(b[3]), Keycode((uint16(b[4])<<8)+uint16(b[5]))) device.flashCh <- true //Changed = true + case 0x07: + // id_lighting_set_value + if device.IsRGBMatrixEnabled() { + switch b[1] { + case 0x41: + // VIALRGB_SET_MODE + rgbId := uint16(b[2]) | (uint16(b[3]) << 8) + device.SetCurrentRGBMode(rgbId) + device.SetCurrentSpeed(b[4]) + device.SetCurrentHSV(b[5], b[6], b[7]) + device.flashCh <- true + case 0x42: + // VIALRGB_DIRECT_FASTSET + if !device.IsDirectModeEnabled() { + break + } + if len(b) < 4 { + break + } + firstIndex := uint16(b[2]) | (uint16(b[3]) << 8) + numLeds := uint16(b[4]) + if int(numLeds)*3 > len(b)-4 { + break + } + var i uint16 + for i = 0; i < numLeds; i++ { + if i+firstIndex >= device.GetRGBMatrixLEDCount() { + break + } + device.SetDirectHSV( + b[i*3+5], + b[i*3+6], + b[i*3+7], + i+firstIndex, + ) + } + } + } case 0x08: // id_lighting_get_value - txb[1] = 0x00 - txb[2] = 0x00 + if device.IsRGBMatrixEnabled() { + switch b[1] { + case 0x40: + // vialrgb_get_info + const vialRgbProtocolVersion = 0x0001 + txb[2] = vialRgbProtocolVersion & 0xFF + txb[3] = vialRgbProtocolVersion >> 8 + txb[4] = device.GetRGBMatrixMaximumBrightness() + case 0x41: + // vialrgb_get_mode + currentEffect := device.GetCurrentRGBMode() + txb[2] = byte(currentEffect & 0xFF) + txb[3] = byte(currentEffect >> 8) + txb[4] = device.GetCurrentSpeed() + txb[5] = device.GetCurrentHue() + txb[6] = device.GetCurrentSaturation() + txb[7] = device.GetCurrentValue() + case 0x42: + // vialrgb_get_supported + implementedEffects := device.GetSupportedRGBModes() + var length int + if len(implementedEffects) > 15 { + length = 15 + } else { + length = len(implementedEffects) + } + for i := 0; i < length; i++ { + txb[i*2] = byte(implementedEffects[i].AnimationType & 0xFF) + txb[i*2+1] = byte(implementedEffects[i].AnimationType >> 8) + } + if length < 16 { + txb[length*2] = 0xFF + txb[length*2+1] = 0xFF + } + case 0x43: + // vialrgb_get_number_leds + if !device.IsDirectModeEnabled() { + break + } + txb[2] = byte(device.GetRGBMatrixLEDCount() & 0xFF) + txb[3] = byte(device.GetRGBMatrixLEDCount() >> 8) + case 0x44: + //vialrgb_get_led_info + if !device.IsDirectModeEnabled() { + break + } + ledPos := uint16(b[2]&0xFF) | (uint16(b[3]) >> 8) + position := device.GetRGBMatrixLEDMapping(ledPos) + // physical position + txb[2] = position.PhysicalX + txb[3] = position.PhysicalY + // flags + txb[4] = position.LedFlags + // matrix position + txb[5] = position.KbIndex + txb[6] = position.MatrixIndex + } + } else { + txb[1] = 0x00 + txb[2] = 0x00 + } case 0xFE: // vial switch b[1] { case 0x00: @@ -216,6 +307,9 @@ func rxHandler2(b []byte) bool { txb[9] = 0xF3 txb[10] = 0x54 txb[11] = 0xE2 + if device.IsRGBMatrixEnabled() { + txb[12] = 1 + } case 0x01: // Retrieve keyboard definition size size := len(KeyboardDef) @@ -258,7 +352,6 @@ func rxHandler2(b []byte) bool { return false } machine.SendUSBInPacket(6, txb[:32]) - //fmt.Printf("Tx % X\n", txb[:32]) return true } @@ -268,7 +361,8 @@ func Save() error { keyboards := device.GetKeyboardCount() cnt := device.GetMaxKeyCount() - wbuf := make([]byte, 4+layers*keyboards*cnt*2+len(device.Macros)) + rgbStorageSize := 2 + 1 + 3 // currentEffect + speed + HSV + wbuf := make([]byte, 4+layers*keyboards*cnt*2+len(device.Macros)+rgbStorageSize) needed := int64(len(wbuf)) / machine.Flash.EraseBlockSize() if needed == 0 { needed = 1 @@ -297,6 +391,14 @@ func Save() error { } } + wbuf[offset] = byte(device.GetCurrentRGBMode()) + wbuf[offset+1] = byte(device.GetCurrentRGBMode() >> 8) + wbuf[offset+2] = device.GetCurrentSpeed() + wbuf[offset+3] = device.GetCurrentHue() + wbuf[offset+4] = device.GetCurrentSaturation() + wbuf[offset+5] = device.GetCurrentValue() + offset += 6 + copy(wbuf[offset:], device.Macros[:]) _, err = machine.Flash.WriteAt(wbuf[:], 0)