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

     1  package joystick
     2  
     3  import (
     4  	"machine"
     5  	"machine/usb"
     6  	"machine/usb/descriptor"
     7  	"machine/usb/hid"
     8  )
     9  
    10  var Joystick *joystick
    11  
    12  type joystick struct {
    13  	State
    14  	buf           *hid.RingBuffer
    15  	waitTxc       bool
    16  	rxHandlerFunc func(b []byte)
    17  	setupFunc     func(setup usb.Setup) bool
    18  }
    19  
    20  func init() {
    21  	if Joystick == nil {
    22  		Joystick = newDefaultJoystick()
    23  	}
    24  }
    25  
    26  // UseSettings overrides the Joystick settings. This function must be
    27  // called from init().
    28  func UseSettings(def Definitions, rxHandlerFunc func(b []byte), setupFunc func(setup usb.Setup) bool, hidDesc []byte) *joystick {
    29  	js := &joystick{
    30  		buf:   hid.NewRingBuffer(),
    31  		State: def.NewState(),
    32  	}
    33  	if setupFunc == nil {
    34  		setupFunc = hid.DefaultSetupHandler
    35  	}
    36  	if rxHandlerFunc == nil {
    37  		rxHandlerFunc = js.rxHandlerFunc
    38  	}
    39  	if len(hidDesc) == 0 {
    40  		hidDesc = descriptor.JoystickDefaultHIDReport
    41  	}
    42  	class, err := descriptor.FindClassHIDType(descriptor.CDCJoystick.Configuration, descriptor.ClassHIDJoystick.Bytes())
    43  	if err != nil {
    44  		// TODO: some way to notify about error
    45  		return nil
    46  	}
    47  
    48  	class.ClassLength(uint16(len(hidDesc)))
    49  	descriptor.CDCJoystick.HID[2] = hidDesc
    50  
    51  	machine.ConfigureUSBEndpoint(descriptor.CDCJoystick,
    52  		[]usb.EndpointConfig{
    53  			{
    54  				Index:     usb.HID_ENDPOINT_OUT,
    55  				IsIn:      false,
    56  				Type:      usb.ENDPOINT_TYPE_INTERRUPT,
    57  				RxHandler: rxHandlerFunc,
    58  			},
    59  			{
    60  				Index:     usb.HID_ENDPOINT_IN,
    61  				IsIn:      true,
    62  				Type:      usb.ENDPOINT_TYPE_INTERRUPT,
    63  				TxHandler: js.handler,
    64  			},
    65  		},
    66  		[]usb.SetupConfig{
    67  			{
    68  				Index:   usb.HID_INTERFACE,
    69  				Handler: setupFunc,
    70  			},
    71  		},
    72  	)
    73  	Joystick = js
    74  	return js
    75  }
    76  
    77  func newDefaultJoystick() *joystick {
    78  	def := DefaultDefinitions()
    79  	js := UseSettings(def, nil, nil, nil)
    80  	return js
    81  }
    82  
    83  // Port returns the USB Joystick port.
    84  func Port() *joystick {
    85  	return Joystick
    86  }
    87  
    88  func (m *joystick) handler() {
    89  	m.waitTxc = false
    90  	if b, ok := m.buf.Get(); ok {
    91  		m.waitTxc = true
    92  		hid.SendUSBPacket(b)
    93  	}
    94  }
    95  
    96  func (m *joystick) tx(b []byte) {
    97  	if machine.USBDev.InitEndpointComplete {
    98  		if m.waitTxc {
    99  			m.buf.Put(b)
   100  		} else {
   101  			m.waitTxc = true
   102  			hid.SendUSBPacket(b)
   103  		}
   104  	}
   105  }
   106  
   107  func (m *joystick) ready() bool {
   108  	return true
   109  }
   110  
   111  func (m *joystick) rxHandler(b []byte) {
   112  	if m.rxHandlerFunc != nil {
   113  		m.rxHandlerFunc(b)
   114  	}
   115  }
   116  
   117  // to InterruptOut
   118  func (m *joystick) SendReport(reportID byte, b []byte) {
   119  	m.tx(append([]byte{reportID}, b...))
   120  }
   121  
   122  func (m *joystick) SendState() {
   123  	b, _ := m.State.MarshalBinary()
   124  	m.tx(b)
   125  }