github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/usb/hid/joystick/state.go (about)

     1  package joystick
     2  
     3  import (
     4  	"machine/usb/descriptor"
     5  
     6  	"encoding/binary"
     7  )
     8  
     9  type HatDirection uint8
    10  
    11  const (
    12  	HatUp HatDirection = iota
    13  	HatRightUp
    14  	HatRight
    15  	HatRightDown
    16  	HatDown
    17  	HatLeftDown
    18  	HatLeft
    19  	HatLeftUp
    20  	HatCenter
    21  )
    22  
    23  type Constraint struct {
    24  	MinIn  int
    25  	MaxIn  int
    26  	MinOut int16
    27  	MaxOut int16
    28  }
    29  
    30  type AxisValue struct {
    31  	constraint Constraint
    32  	Value      int
    33  }
    34  
    35  func fit(x, in_min, in_max int, out_min, out_max int16) int16 {
    36  	return int16((x-in_min)*(int(out_max)-int(out_min))/(in_max-in_min) + int(out_min))
    37  }
    38  
    39  func fitf(x, in_min, in_max, out_min, out_max float32) float32 {
    40  	return x - in_min*(out_max-out_min)/(in_max-in_min) + out_min
    41  }
    42  
    43  func limit(v, max int) int {
    44  	if v > max {
    45  		v = max
    46  	} else if v < -max {
    47  		v = -max
    48  	}
    49  	return v
    50  }
    51  
    52  type Definitions struct {
    53  	ReportID     byte
    54  	ButtonCnt    int
    55  	HatSwitchCnt int
    56  	AxisDefs     []Constraint
    57  	descriptor   []byte
    58  }
    59  
    60  func (c Definitions) Descriptor() []byte {
    61  	if len(c.descriptor) > 0 {
    62  		return c.descriptor
    63  	}
    64  	// TODO: build hid descriptor
    65  	return nil
    66  }
    67  
    68  func (c Definitions) NewState() State {
    69  	bufSize := 1
    70  	axises := make([]*AxisValue, 0, len(c.AxisDefs))
    71  	for _, v := range c.AxisDefs {
    72  
    73  		axises = append(axises, &AxisValue{
    74  			constraint: v,
    75  			Value:      0,
    76  		})
    77  	}
    78  	btnSize := (c.ButtonCnt + 7) / 8
    79  	bufSize += btnSize
    80  	if c.HatSwitchCnt > 0 {
    81  		bufSize++
    82  	}
    83  	bufSize += len(axises) * 2
    84  	initBuf := make([]byte, bufSize)
    85  	initBuf[0] = c.ReportID
    86  	return State{
    87  		buf:         initBuf,
    88  		Buttons:     make([]byte, btnSize),
    89  		HatSwitches: make([]HatDirection, c.HatSwitchCnt),
    90  		Axises:      axises,
    91  	}
    92  }
    93  
    94  type State struct {
    95  	buf         []byte
    96  	Buttons     []byte
    97  	HatSwitches []HatDirection
    98  	Axises      []*AxisValue
    99  }
   100  
   101  func (s State) MarshalBinary() ([]byte, error) {
   102  	s.buf = s.buf[0:1]
   103  	s.buf = append(s.buf, s.Buttons...)
   104  	if len(s.HatSwitches) > 0 {
   105  		hat := byte(0)
   106  		for _, v := range s.HatSwitches {
   107  			hat <<= 4
   108  			hat |= byte(v & 0xf)
   109  		}
   110  		s.buf = append(s.buf, hat)
   111  	}
   112  	for _, v := range s.Axises {
   113  		c := v.constraint
   114  		val := fit(v.Value, c.MinIn, c.MaxIn, c.MinOut, c.MaxOut)
   115  		s.buf = binary.LittleEndian.AppendUint16(s.buf, uint16(val))
   116  	}
   117  	return s.buf, nil
   118  }
   119  
   120  func (s State) Button(index int) bool {
   121  	idx := index / 8
   122  	bit := uint8(1 << (index % 8))
   123  	return s.Buttons[idx]&bit > 0
   124  }
   125  
   126  func (s State) SetButton(index int, push bool) {
   127  	idx := index / 8
   128  	bit := uint8(1 << (index % 8))
   129  	b := s.Buttons[idx]
   130  	b &= ^bit
   131  	if push {
   132  		b |= bit
   133  	}
   134  	s.Buttons[idx] = b
   135  }
   136  
   137  func (s State) Hat(index int) HatDirection {
   138  	return s.HatSwitches[index]
   139  }
   140  
   141  func (s State) SetHat(index int, dir HatDirection) {
   142  	s.HatSwitches[index] = dir
   143  }
   144  
   145  func (s State) Axis(index int) int {
   146  	return s.Axises[index].Value
   147  }
   148  
   149  func (s State) SetAxis(index int, v int) {
   150  	s.Axises[index].Value = v
   151  }
   152  
   153  func DefaultDefinitions() Definitions {
   154  	return Definitions{
   155  		ReportID:     1,
   156  		ButtonCnt:    16,
   157  		HatSwitchCnt: 1,
   158  		AxisDefs: []Constraint{
   159  			{MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767},
   160  			{MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767},
   161  			{MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767},
   162  			{MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767},
   163  			{MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767},
   164  			{MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767},
   165  		},
   166  		descriptor: descriptor.JoystickDefaultHIDReport,
   167  	}
   168  }