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 }