github.com/stampzilla/stampzilla-go@v2.0.0-rc9+incompatible/nodes/stampzilla-streamdeck/streamdeck/streamdeck.go (about)

     1  package streamdeck
     2  
     3  import (
     4  	"image"
     5  	"log"
     6  
     7  	"github.com/davecgh/go-spew/spew"
     8  	"github.com/stamp/hid"
     9  )
    10  
    11  var NUM_KEYS = 15
    12  var ICON_SIZE = 72
    13  
    14  var NUM_FIRST_PAGE_PIXELS = 2583
    15  var NUM_SECOND_PAGE_PIXELS = 2601
    16  
    17  var reset = []byte{0x0B, 0x63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    18  
    19  var brightnessBytes = []byte{0x05, 0x55, 0xAA, 0xD1, 0x01, 0, 0x00,
    20  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
    21  
    22  var streamDeck *hid.Device
    23  
    24  type StreamDeck struct {
    25  	DeviceInfo hid.DeviceInfo
    26  	Device     *hid.Device
    27  
    28  	callbacks map[string][]func(button int, state bool)
    29  }
    30  
    31  func FindDecks() []*StreamDeck {
    32  	devices := hid.Enumerate(4057, 96)
    33  
    34  	decks := []*StreamDeck{}
    35  	for _, deviceInfo := range devices {
    36  		decks = append(decks, &StreamDeck{
    37  			DeviceInfo: deviceInfo,
    38  			callbacks:  make(map[string][]func(button int, state bool)),
    39  		})
    40  	}
    41  
    42  	spew.Dump(decks)
    43  
    44  	return decks
    45  }
    46  
    47  func (deck *StreamDeck) Open() error {
    48  	var err error
    49  	deck.Device, err = deck.DeviceInfo.Open()
    50  	if err != nil {
    51  		return err
    52  	}
    53  	go deck.readLoop()
    54  
    55  	return nil
    56  }
    57  
    58  func (deck *StreamDeck) Close() {
    59  	deck.Device.Close()
    60  }
    61  
    62  func (deck *StreamDeck) Reset() error {
    63  	_, err := deck.Device.SendFeatureReport(reset)
    64  	return err
    65  }
    66  
    67  func (deck *StreamDeck) SetBrightness(brightness int) error {
    68  	brightnessBytes[5] = byte(brightness)
    69  
    70  	_, err := deck.Device.SendFeatureReport(brightnessBytes)
    71  	return err
    72  }
    73  
    74  func (deck *StreamDeck) WriteImageToKey(image *image.RGBA, key int) {
    75  	pixels := make([]byte, ICON_SIZE*ICON_SIZE*3)
    76  
    77  	for r := 0; r < ICON_SIZE; r++ {
    78  		rowStartImage := r * ICON_SIZE * 4
    79  		rowStartPixels := r * ICON_SIZE * 3
    80  		for c := 0; c < ICON_SIZE; c++ {
    81  			colPosImage := (c * 4) + rowStartImage
    82  			colPosPixels := (ICON_SIZE * 3) + rowStartPixels - (c * 3) - 1
    83  
    84  			pixels[colPosPixels-2] = image.Pix[colPosImage+2]
    85  			pixels[colPosPixels-1] = image.Pix[colPosImage+1]
    86  			pixels[colPosPixels] = image.Pix[colPosImage]
    87  		}
    88  	}
    89  
    90  	writePage1(deck.Device, key, pixels[0:NUM_FIRST_PAGE_PIXELS*3])
    91  	writePage2(deck.Device, key, pixels[NUM_FIRST_PAGE_PIXELS*3:])
    92  }
    93  
    94  func (deck *StreamDeck) OnKeyDown(callback func(button int, state bool)) {
    95  	deck.on("down", callback)
    96  }
    97  func (deck *StreamDeck) OnKeyUp(callback func(button int, state bool)) {
    98  	deck.on("up", callback)
    99  }
   100  func (deck *StreamDeck) OnKeyChange(callback func(button int, state bool)) {
   101  	deck.on("change", callback)
   102  }
   103  func (deck *StreamDeck) on(event string, callback func(button int, state bool)) {
   104  	deck.callbacks[event] = append(deck.callbacks[event], callback)
   105  }
   106  
   107  func writePage1(sd *hid.Device, key int, pixels []byte) error {
   108  	header := []byte{
   109  		0x02, 0x01, 0x01, 0x00, 0x00, (byte)(key + 1), 0x00, 0x00,
   110  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   111  		0x42, 0x4d, 0xf6, 0x3c, 0x00, 0x00, 0x00, 0x00,
   112  		0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
   113  		0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00,
   114  		0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
   115  		0x00, 0x00, 0xc0, 0x3c, 0x00, 0x00, 0xc4, 0x0e,
   116  		0x00, 0x00, 0xc4, 0x0e, 0x00, 0x00, 0x00, 0x00,
   117  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   118  	}
   119  
   120  	header = append(header, pixels...)
   121  
   122  	data := make([]byte, 8191)
   123  
   124  	copy(data, header)
   125  
   126  	_, err := sd.Write(data)
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	return nil
   132  }
   133  
   134  func writePage2(sd *hid.Device, key int, pixels []byte) error {
   135  	header := []byte{
   136  		0x02, 0x01, 0x02, 0x00, 0x01, (byte)(key + 1),
   137  	}
   138  
   139  	padding := make([]byte, 10)
   140  
   141  	header = append(header, padding...)
   142  	header = append(header, pixels...)
   143  
   144  	data := make([]byte, 8191)
   145  
   146  	copy(data, header)
   147  
   148  	_, err := sd.Write(data)
   149  	if err != nil {
   150  		return err
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  func (deck *StreamDeck) readLoop() {
   157  	data := make([]byte, 255)
   158  
   159  	var keyState [15]bool
   160  
   161  	for {
   162  		size, err := deck.Device.Read(data)
   163  		if err != nil {
   164  			log.Println("Failed to read from streamdeck: ", err)
   165  			return
   166  		}
   167  
   168  		for k, v := range data[1 : size-1] {
   169  			state := v > 0
   170  			if keyState[k] != state {
   171  				keyState[k] = state
   172  
   173  				for _, callback := range deck.callbacks["change"] {
   174  					callback(k, state)
   175  				}
   176  				if state {
   177  					for _, callback := range deck.callbacks["down"] {
   178  						callback(k, state)
   179  					}
   180  				} else {
   181  					for _, callback := range deck.callbacks["up"] {
   182  						callback(k, state)
   183  					}
   184  				}
   185  			}
   186  		}
   187  	}
   188  }