diff options
author | sago35 <[email protected]> | 2022-06-02 08:29:13 +0900 |
---|---|---|
committer | Ron Evans <[email protected]> | 2022-06-11 09:44:09 +0200 |
commit | 1b2e764835fb5278de144caf059cb094bad4db23 (patch) | |
tree | 1a28c06af78d4a1d2db023a752817ae2ecc42808 | |
parent | 2c93a4085cf3b8783d10129698ddaaa2d9e1fbc4 (diff) | |
download | tinygo-1b2e764835fb5278de144caf059cb094bad4db23.tar.gz tinygo-1b2e764835fb5278de144caf059cb094bad4db23.zip |
samd21,samd51,nrf52840: add support for USBHID (keyboard / mouse)
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | src/examples/hid-keyboard/main.go | 21 | ||||
-rw-r--r-- | src/examples/hid-mouse/main.go | 37 | ||||
-rw-r--r-- | src/machine/machine_atsamd21.go | 53 | ||||
-rw-r--r-- | src/machine/machine_atsamd51.go | 54 | ||||
-rw-r--r-- | src/machine/machine_nrf52840_usb.go | 49 | ||||
-rw-r--r-- | src/machine/usb.go | 493 | ||||
-rw-r--r-- | src/machine/usb/hid/buffer.go | 52 | ||||
-rw-r--r-- | src/machine/usb/hid/hid.go | 51 | ||||
-rw-r--r-- | src/machine/usb/hid/keyboard/keyboard.go | 478 | ||||
-rw-r--r-- | src/machine/usb/hid/keyboard/keycode.go | 532 | ||||
-rw-r--r-- | src/machine/usb/hid/mouse/mouse.go | 90 | ||||
-rw-r--r-- | src/machine/usb_descriptor.go | 70 |
13 files changed, 1510 insertions, 479 deletions
@@ -414,6 +414,10 @@ smoketest: @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=pca10040 examples/test @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse + @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard + @$(MD5SUM) test.hex # test simulated boards on play.tinygo.org ifneq ($(WASM), 0) $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1 @@ -555,6 +559,11 @@ endif @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm @$(MD5SUM) test.hex + # test usbhid + $(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/hid-keyboard + @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/hid-keyboard + @$(MD5SUM) test.hex ifneq ($(STM32), 0) $(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1 @$(MD5SUM) test.hex diff --git a/src/examples/hid-keyboard/main.go b/src/examples/hid-keyboard/main.go new file mode 100644 index 000000000..9f0c478b7 --- /dev/null +++ b/src/examples/hid-keyboard/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "machine" + "machine/usb/hid/keyboard" + "time" +) + +func main() { + button := machine.BUTTON + button.Configure(machine.PinConfig{Mode: machine.PinInputPullup}) + + kb := keyboard.New() + + for { + if !button.Get() { + kb.Write([]byte("tinygo")) + time.Sleep(200 * time.Millisecond) + } + } +} diff --git a/src/examples/hid-mouse/main.go b/src/examples/hid-mouse/main.go new file mode 100644 index 000000000..1617c6b6a --- /dev/null +++ b/src/examples/hid-mouse/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "machine" + "machine/usb/hid/mouse" + "time" +) + +func main() { + button := machine.BUTTON + button.Configure(machine.PinConfig{Mode: machine.PinInputPullup}) + + mouse := mouse.New() + + for { + if !button.Get() { + for j := 0; j < 5; j++ { + for i := 0; i < 100; i++ { + mouse.Move(1, 0) + time.Sleep(1 * time.Millisecond) + } + + for i := 0; i < 100; i++ { + mouse.Move(0, 1) + time.Sleep(1 * time.Millisecond) + } + + for i := 0; i < 100; i++ { + mouse.Move(-1, -1) + time.Sleep(1 * time.Millisecond) + } + } + + time.Sleep(100 * time.Millisecond) + } + } +} diff --git a/src/machine/machine_atsamd21.go b/src/machine/machine_atsamd21.go index 9b18a3130..d88190254 100644 --- a/src/machine/machine_atsamd21.go +++ b/src/machine/machine_atsamd21.go @@ -1746,7 +1746,8 @@ type USBCDC struct { } var ( - USB = &USBCDC{Buffer: NewRingBuffer()} + USB = &USBCDC{Buffer: NewRingBuffer()} + waitHidTxc bool ) const ( @@ -1999,6 +2000,9 @@ func handleUSB(intr interrupt.Interrupt) { if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 { USB.Flush() // if you want to blink LED showing traffic, this would be the place... + if hidCallback != nil && !waitHidTxc { + hidCallback() + } } // Endpoint 0 Setup interrupt @@ -2021,6 +2025,9 @@ func handleUSB(intr interrupt.Interrupt) { // Class Interface Requests if setup.wIndex == usb_CDC_ACM_INTERFACE { ok = cdcSetup(setup) + } else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE { + sendZlp() + ok = true } } @@ -2059,6 +2066,9 @@ func handleUSB(intr interrupt.Interrupt) { if i == usb_CDC_ENDPOINT_IN { USB.waitTxc = false } + case usb_HID_ENDPOINT_IN: + setEPINTFLAG(i, sam.USB_DEVICE_EPINTFLAG_TRCPT1) + waitHidTxc = false } } } @@ -2156,7 +2166,7 @@ func handleStandardSetup(setup usbSetup) bool { } } - sendUSBPacket(0, buf) + sendUSBPacket(0, buf, setup.wLength) return true case usb_CLEAR_FEATURE: @@ -2212,7 +2222,7 @@ func handleStandardSetup(setup usbSetup) bool { case usb_GET_CONFIGURATION: buff := []byte{usbConfiguration} - sendUSBPacket(0, buff) + sendUSBPacket(0, buff, setup.wLength) return true case usb_SET_CONFIGURATION: @@ -2229,6 +2239,11 @@ func handleStandardSetup(setup usbSetup) bool { // Enable interrupt for CDC data messages from host setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_EPINTENSET_TRCPT0) + // Enable interrupt for HID messages from host + if hidCallback != nil { + setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_EPINTENSET_TRCPT1) + } + sendZlp() return true } else { @@ -2237,7 +2252,7 @@ func handleStandardSetup(setup usbSetup) bool { case usb_GET_INTERFACE: buff := []byte{usbSetInterface} - sendUSBPacket(0, buff) + sendUSBPacket(0, buff, setup.wLength) return true case usb_SET_INTERFACE: @@ -2263,7 +2278,7 @@ func cdcSetup(setup usbSetup) bool { b[5] = byte(usbLineInfo.bParityType) b[6] = byte(usbLineInfo.bDataBits) - sendUSBPacket(0, b[:]) + sendUSBPacket(0, b[:], setup.wLength) return true } } @@ -2306,9 +2321,31 @@ func cdcSetup(setup usbSetup) bool { return false } +// SendUSBHIDPacket sends a packet for USBHID (interrupt / in). +func SendUSBHIDPacket(ep uint32, data []byte) bool { + if waitHidTxc { + return false + } + sendUSBPacket(ep, data, 0) + + // clear transfer complete flag + setEPINTFLAG(ep, sam.USB_DEVICE_EPINTFLAG_TRCPT1) + + // send data by setting bank ready + setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_BK1RDY) + + waitHidTxc = true + + return true +} + //go:noinline -func sendUSBPacket(ep uint32, data []byte) { - copy(udd_ep_in_cache_buffer[ep][:], data) +func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { + l := uint16(len(data)) + if 0 < maxsize && maxsize < l { + l = maxsize + } + copy(udd_ep_in_cache_buffer[ep][:], data[:l]) // Set endpoint address for sending data usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) @@ -2318,7 +2355,7 @@ func sendUSBPacket(ep uint32, data []byte) { // set byte count, which is total number of bytes to be sent usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)) + usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) } func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) { diff --git a/src/machine/machine_atsamd51.go b/src/machine/machine_atsamd51.go index 65effd594..db2fea71e 100644 --- a/src/machine/machine_atsamd51.go +++ b/src/machine/machine_atsamd51.go @@ -1987,7 +1987,8 @@ type USBCDC struct { var ( // USB is a USB CDC interface. - USB = &USBCDC{Buffer: NewRingBuffer()} + USB = &USBCDC{Buffer: NewRingBuffer()} + waitHidTxc bool ) const ( @@ -2241,6 +2242,9 @@ func handleUSBIRQ(interrupt.Interrupt) { // Start of frame if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 { USB.Flush() + if hidCallback != nil && !waitHidTxc { + hidCallback() + } // if you want to blink LED showing traffic, this would be the place... } @@ -2264,6 +2268,9 @@ func handleUSBIRQ(interrupt.Interrupt) { // Class Interface Requests if setup.wIndex == usb_CDC_ACM_INTERFACE { ok = cdcSetup(setup) + } else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE { + sendZlp() + ok = true } } @@ -2302,6 +2309,9 @@ func handleUSBIRQ(interrupt.Interrupt) { if i == usb_CDC_ENDPOINT_IN { USB.waitTxc = false } + case usb_HID_ENDPOINT_IN: + setEPINTFLAG(i, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) + waitHidTxc = false } } } @@ -2399,7 +2409,7 @@ func handleStandardSetup(setup usbSetup) bool { } } - sendUSBPacket(0, buf) + sendUSBPacket(0, buf, setup.wLength) return true case usb_CLEAR_FEATURE: @@ -2455,7 +2465,7 @@ func handleStandardSetup(setup usbSetup) bool { case usb_GET_CONFIGURATION: buff := []byte{usbConfiguration} - sendUSBPacket(0, buff) + sendUSBPacket(0, buff, setup.wLength) return true case usb_SET_CONFIGURATION: @@ -2472,6 +2482,11 @@ func handleStandardSetup(setup usbSetup) bool { // Enable interrupt for CDC data messages from host setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0) + // Enable interrupt for HID messages from host + if hidCallback != nil { + setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1) + } + sendZlp() return true } else { @@ -2480,7 +2495,7 @@ func handleStandardSetup(setup usbSetup) bool { case usb_GET_INTERFACE: buff := []byte{usbSetInterface} - sendUSBPacket(0, buff) + sendUSBPacket(0, buff, setup.wLength) return true case usb_SET_INTERFACE: @@ -2506,7 +2521,7 @@ func cdcSetup(setup usbSetup) bool { b[5] = byte(usbLineInfo.bParityType) b[6] = byte(usbLineInfo.bDataBits) - sendUSBPacket(0, b[:]) + sendUSBPacket(0, b[:], setup.wLength) return true } } @@ -2549,9 +2564,32 @@ func cdcSetup(setup usbSetup) bool { return false } +// SendUSBHIDPacket sends a packet for USBHID (interrupt / in). +func SendUSBHIDPacket(ep uint32, data []byte) bool { + if waitHidTxc { + return false + } + + sendUSBPacket(ep, data, 0) + + // clear transfer complete flag + setEPINTFLAG(ep, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) + + // send data by setting bank ready + setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY) + + waitHidTxc = true + + return true +} + //go:noinline -func sendUSBPacket(ep uint32, data []byte) { - copy(udd_ep_in_cache_buffer[ep][:], data) +func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { + l := uint16(len(data)) + if 0 < maxsize && maxsize < l { + l = maxsize + } + copy(udd_ep_in_cache_buffer[ep][:], data[:l]) // Set endpoint address for sending data usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) @@ -2561,7 +2599,7 @@ func sendUSBPacket(ep uint32, data []byte) { // set byte count, which is total number of bytes to be sent usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)) + usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) } func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) { diff --git a/src/machine/machine_nrf52840_usb.go b/src/machine/machine_nrf52840_usb.go index 098424a35..7260ac15f 100644 --- a/src/machine/machine_nrf52840_usb.go +++ b/src/machine/machine_nrf52840_usb.go @@ -121,8 +121,9 @@ func (usbcdc *USBCDC) RTS() bool { } var ( - USB = &_USB - _USB = USBCDC{Buffer: NewRingBuffer()} + USB = &_USB + _USB = USBCDC{Buffer: NewRingBuffer()} + waitHidTxc bool usbEndpointDescriptors [8]usbDeviceDescriptor @@ -201,6 +202,9 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) { if nrf.USBD.EVENTS_SOF.Get() == 1 { nrf.USBD.EVENTS_SOF.Set(0) usbcdc.Flush() + if hidCallback != nil && !waitHidTxc { + hidCallback() + } // if you want to blink LED showing traffic, this would be the place... } @@ -262,6 +266,9 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) { } else { if setup.wIndex == usb_CDC_ACM_INTERFACE { ok = cdcSetup(setup) + } else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE { + sendZlp() + ok = true } } @@ -297,6 +304,8 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) { usbcdc.waitTxc = false exitCriticalSection() } + case usb_HID_ENDPOINT_IN: + waitHidTxc = false } } } @@ -378,7 +387,7 @@ func handleStandardSetup(setup usbSetup) bool { } } - sendUSBPacket(0, buf) + sendUSBPacket(0, buf, setup.wLength) return true case usb_CLEAR_FEATURE: @@ -412,7 +421,7 @@ func handleStandardSetup(setup usbSetup) bool { case usb_GET_CONFIGURATION: buff := []byte{usbConfiguration} - sendUSBPacket(0, buff) + sendUSBPacket(0, buff, setup.wLength) return true case usb_SET_CONFIGURATION: @@ -422,6 +431,11 @@ func handleStandardSetup(setup usbSetup) bool { initEndpoint(uint32(i), endPoints[i]) } + // Enable interrupt for HID messages from host + if hidCallback != nil { + nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 << usb_HID_ENDPOINT_IN) + } + usbConfiguration = setup.wValueL return true } else { @@ -430,7 +444,7 @@ func handleStandardSetup(setup usbSetup) bool { case usb_GET_INTERFACE: buff := []byte{usbSetInterface} - sendUSBPacket(0, buff) + sendUSBPacket(0, buff, setup.wLength) return true case usb_SET_INTERFACE: @@ -456,7 +470,7 @@ func cdcSetup(setup usbSetup) bool { b[5] = byte(usbLineInfo.bParityType) b[6] = byte(usbLineInfo.bDataBits) - sendUSBPacket(0, b[:]) + sendUSBPacket(0, b[:], setup.wLength) return true } } @@ -482,10 +496,29 @@ func cdcSetup(setup usbSetup) bool { return false } +// SendUSBHIDPacket sends a packet for USBHID (interrupt / in). +func SendUSBHIDPacket(ep uint32, data []byte) bool { + if waitHidTxc { + return false + } + + sendUSBPacket(ep, data, 0) + + // clear transfer complete flag + nrf.USBD.INTENCLR.Set(nrf.USBD_INTENCLR_ENDEPOUT0 << 4) + + waitHidTxc = true + + return true +} + //go:noinline -func sendUSBPacket(ep uint32, data []byte) { +func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { count := len(data) - copy(udd_ep_in_cache_buffer[ep][:], data) + if 0 < int(maxsize) && int(maxsize) < count { + count = int(maxsize) + } + copy(udd_ep_in_cache_buffer[ep][:], data[:count]) if ep == 0 && count > usbEndpointPacketSize { sendOnEP0DATADONE.ptr = &udd_ep_in_cache_buffer[ep][usbEndpointPacketSize] sendOnEP0DATADONE.count = count - usbEndpointPacketSize diff --git a/src/machine/usb.go b/src/machine/usb.go index 1789e170a..354bc1b14 100644 --- a/src/machine/usb.go +++ b/src/machine/usb.go @@ -8,7 +8,7 @@ import ( "runtime/volatile" ) -const deviceDescriptorSize = 18 +var usbDescriptor = descriptorCDC var ( errUSBCDCBufferEmpty = errors.New("USB-CDC buffer empty") @@ -17,397 +17,6 @@ var ( errUSBCDCBytesRead = errors.New("USB-CDC invalid number of bytes read") ) -// DeviceDescriptor implements the USB standard device descriptor. -// -// Table 9-8. Standard Device Descriptor -// bLength, bDescriptorType, bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0, -// idVendor, idProduct, bcdDevice, iManufacturer, iProduct, iSerialNumber, bNumConfigurations */ -// -type DeviceDescriptor struct { - bLength uint8 // 18 - bDescriptorType uint8 // 1 USB_DEVICE_DESCRIPTOR_TYPE - bcdUSB uint16 // 0x200 - bDeviceClass uint8 - bDeviceSubClass uint8 - bDeviceProtocol uint8 - bMaxPacketSize0 uint8 // Packet 0 - idVendor uint16 - idProduct uint16 - bcdDevice uint16 // 0x100 - iManufacturer uint8 - iProduct uint8 - iSerialNumber uint8 - bNumConfigurations uint8 -} - -// NewDeviceDescriptor returns a USB DeviceDescriptor. -func NewDeviceDescriptor(class, subClass, proto, packetSize0 uint8, vid, pid, version uint16, im, ip, is, configs uint8) DeviceDescriptor { - return DeviceDescriptor{deviceDescriptorSize, 1, 0x200, class, subClass, proto, packetSize0, vid, pid, version, im, ip, is, configs} -} - -// Bytes returns DeviceDescriptor data -func (d DeviceDescriptor) Bytes() [deviceDescriptorSize]byte { - var b [deviceDescriptorSize]byte - b[0] = byte(d.bLength) - b[1] = byte(d.bDescriptorType) - b[2] = byte(d.bcdUSB) - b[3] = byte(d.bcdUSB >> 8) - b[4] = byte(d.bDeviceClass) - b[5] = byte(d.bDeviceSubClass) - b[6] = byte(d.bDeviceProtocol) - b[7] = byte(d.bMaxPacketSize0) - b[8] = byte(d.idVendor) - b[9] = byte(d.idVendor >> 8) - b[10] = byte(d.idProduct) - b[11] = byte(d.idProduct >> 8) - b[12] = byte(d.bcdDevice) - b[13] = byte(d.bcdDevice >> 8) - b[14] = byte(d.iManufacturer) - b[15] = byte(d.iProduct) - b[16] = byte(d.iSerialNumber) - b[17] = byte(d.bNumConfigurations) - return b -} - -const configDescriptorSize = 9 - -// ConfigDescriptor implements the standard USB configuration descriptor. -// -// Table 9-10. Standard Configuration Descriptor -// bLength, bDescriptorType, wTotalLength, bNumInterfaces, bConfigurationValue, iConfiguration -// bmAttributes, bMaxPower -// -type ConfigDescriptor struct { - bLength uint8 // 9 - bDescriptorType uint8 // 2 - wTotalLength uint16 // total length - bNumInterfaces uint8 - bConfigurationValue uint8 - iConfiguration uint8 - bmAttributes uint8 - bMaxPower uint8 -} - -// NewConfigDescriptor returns a new USB ConfigDescriptor. -func NewConfigDescriptor(totalLength uint16, interfaces uint8) ConfigDescriptor { - return ConfigDescriptor{configDescriptorSize, 2, totalLength, interfaces, 1, 0, usb_CONFIG_BUS_POWERED | usb_CONFIG_REMOTE_WAKEUP, 50} -} - -// Bytes returns ConfigDescriptor data. -func (d ConfigDescriptor) Bytes() [configDescriptorSize]byte { - var b [configDescriptorSize]byte - b[0] = byte(d.bLength) - b[1] = byte(d.bDescriptorType) - b[2] = byte(d.wTotalLength) - b[3] = byte(d.wTotalLength >> 8) - b[4] = byte(d.bNumInterfaces) - b[5] = byte(d.bConfigurationValue) - b[6] = byte(d.iConfiguration) - b[7] = byte(d.bmAttributes) - b[8] = byte(d.bMaxPower) - return b -} - -const interfaceDescriptorSize = 9 - -// InterfaceDescriptor implements the standard USB interface descriptor. -// -// Table 9-12. Standard Interface Descriptor -// bLength, bDescriptorType, bInterfaceNumber, bAlternateSetting, bNumEndpoints, bInterfaceClass, -// bInterfaceSubClass, bInterfaceProtocol, iInterface -// -type InterfaceDescriptor struct { - bLength uint8 // 9 - bDescriptorType uint8 // 4 - bInterfaceNumber uint8 - bAlternateSetting uint8 - bNumEndpoints uint8 - bInterfaceClass uint8 - bInterfaceSubClass uint8 - bInterfaceProtocol uint8 - iInterface uint8 -} - -// NewInterfaceDescriptor returns a new USB InterfaceDescriptor. -func NewInterfaceDescriptor(n, numEndpoints, class, subClass, protocol uint8) InterfaceDescriptor { - return InterfaceDescriptor{interfaceDescriptorSize, 4, n, 0, numEndpoints, class, subClass, protocol, 0} -} - -// Bytes returns InterfaceDescriptor data. -func (d InterfaceDescriptor) Bytes() [interfaceDescriptorSize]byte { - var b [interfaceDescriptorSize]byte - b[0] = byte(d.bLength) - b[1] = byte(d.bDescriptorType) - b[2] = byte(d.bInterfaceNumber) - b[3] = byte(d.bAlternateSetting) - b[4] = byte(d.bNumEndpoints) - b[5] = byte(d.bInterfaceClass) - b[6] = byte(d.bInterfaceSubClass) - b[7] = byte(d.bInterfaceProtocol) - b[8] = byte(d.iInterface) - return b -} - -const endpointDescriptorSize = 7 - -// EndpointDescriptor implements the standard USB endpoint descriptor. -// -// Table 9-13. Standard Endpoint Descriptor -// bLength, bDescriptorType, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval -// -type EndpointDescriptor struct { - bLength uint8 // 7 - bDescriptorType uint8 // 5 - bEndpointAddress uint8 - bmAttributes uint8 - wMaxPacketSize uint16 - bInterval uint8 -} - -// NewEndpointDescriptor returns a new USB EndpointDescriptor. -func NewEndpointDescriptor(addr, attr uint8, packetSize uint16, interval uint8) EndpointDescriptor { - return EndpointDescriptor{endpointDescriptorSize, 5, addr, attr, packetSize, interval} -} - -// Bytes returns EndpointDescriptor data. -func (d EndpointDescriptor) Bytes() [endpointDescriptorSize]byte { - var b [endpointDescriptorSize]byte - b[0] = byte(d.bLength) - b[1] = byte(d.bDescriptorType) - b[2] = byte(d.bEndpointAddress) - b[3] = byte(d.bmAttributes) - b[4] = byte(d.wMaxPacketSize) - b[5] = byte(d.wMaxPacketSize >> 8) - b[6] = byte(d.bInterval) - return b -} - -const iadDescriptorSize = 8 - -// IADDescriptor is an Interface Association Descriptor, which is used -// to bind 2 interfaces together in CDC composite device. -// -// Standard Interface Association Descriptor: -// bLength, bDescriptorType, bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, -// bFunctionProtocol, iFunction -// -type IADDescriptor struct { - bLength uint8 // 8 - bDescriptorType uint8 // 11 - bFirstInterface uint8 - bInterfaceCount uint8 - bFunctionClass uint8 - bFunctionSubClass uint8 - bFunctionProtocol uint8 - iFunction uint8 -} - -// NewIADDescriptor returns a new USB IADDescriptor. -func NewIADDescriptor(firstInterface, count, class, subClass, protocol uint8) IADDescriptor { - return IADDescriptor{iadDescriptorSize, 11, firstInterface, count, class, subClass, protocol, 0} -} - -// Bytes returns IADDescriptor data. -func (d IADDescriptor) Bytes() [iadDescriptorSize]byte { - var b [iadDescriptorSize]byte - b[0] = byte(d.bLength) - b[1] = byte(d.bDescriptorType) - b[2] = byte(d.bFirstInterface) - b[3] = byte(d.bInterfaceCount) - b[4] = byte(d.bFunctionClass) - b[5] = byte(d.bFunctionSubClass) - b[6] = byte(d.bFunctionProtocol) - b[7] = byte(d.iFunction) - return b -} - -const cdcCSInterfaceDescriptorSize = 5 - -// CDCCSInterfaceDescriptor is a CDC CS interface descriptor. -type CDCCSInterfaceDescriptor struct { - len uint8 // 5 - dtype uint8 // 0x24 - subtype uint8 - d0 uint8 - d1 uint8 -} - -// NewCDCCSInterfaceDescriptor returns a new USB CDCCSInterfaceDescriptor. -func NewCDCCSInterfaceDescriptor(subtype, d0, d1 uint8) CDCCSInterfaceDescriptor { - return CDCCSInterfaceDescriptor{cdcCSInterfaceDescriptorSize, 0x24, subtype, d0, d1} -} - -// Bytes returns CDCCSInterfaceDescriptor data. -func (d CDCCSInterfaceDescriptor) Bytes() [cdcCSInterfaceDescriptorSize]byte { - var b [cdcCSInterfaceDescriptorSize]byte - b[0] = byte(d.len) - b[1] = byte(d.dtype) - b[2] = byte(d.subtype) - b[3] = byte(d.d0) - b[4] = byte(d.d1) - return b -} - -const cmFunctionalDescriptorSize = 5 - -// CMFunctionalDescriptor is the functional descriptor general format. -type CMFunctionalDescriptor struct { - bFunctionLength uint8 - bDescriptorType uint8 // 0x24 - bDescriptorSubtype uint8 // 1 - bmCapabilities uint8 - bDataInterface uint8 -} - -// NewCMFunctionalDescriptor returns a new USB CMFunctionalDescriptor. -func NewCMFunctionalDescriptor(subtype, d0, d1 uint8) CMFunctionalDescriptor { - return CMFunctionalDescriptor{5, 0x24, subtype, d0, d1} -} - -// Bytes returns the CMFunctionalDescriptor data. -func (d CMFunctionalDescriptor) Bytes() [cmFunctionalDescriptorSize]byte { - var b [cmFunctionalDescriptorSize]byte - b[0] = byte(d.bFunctionLength) - b[1] = byte(d.bDescriptorType) - b[2] = byte(d.bDescriptorSubtype) - b[3] = byte(d.bmCapabilities) - b[4] = byte(d.bDescriptorSubtype) - return b -} - -const acmFunctionalDescriptorSize = 4 - -// ACMFunctionalDescriptor is a Abstract Control Model (ACM) USB descriptor. -type ACMFunctionalDescriptor struct { - len uint8 - dtype uint8 // 0x24 - subtype uint8 // 1 - bmCapabilities uint8 -} - -// NewACMFunctionalDescriptor returns a new USB ACMFunctionalDescriptor. -func NewACMFunctionalDescriptor(subtype, d0 uint8) ACMFunctionalDescriptor { - return ACMFunctionalDescriptor{4, 0x24, subtype, d0} -} - -// Bytes returns the ACMFunctionalDescriptor data. -func (d ACMFunctionalDescriptor) Bytes() [acmFunctionalDescriptorSize]byte { - var b [acmFunctionalDescriptorSize]byte - b[0] = byte(d.len) - b[1] = byte(d.dtype) - b[2] = byte(d.subtype) - b[3] = byte(d.bmCapabilities) - return b -} - -// CDCDescriptor is the Communication Device Class (CDC) descriptor. -type CDCDescriptor struct { - // IAD - iad IADDescriptor // Only needed on compound device - - // Control - cif InterfaceDescriptor - header CDCCSInterfaceDescriptor - - // CDC control - controlManagement ACMFunctionalDescriptor // ACM - functionalDescriptor CDCCSInterfaceDescriptor // CDC_UNION - callManagement CMFunctionalDescriptor // Call Management - cifin EndpointDescriptor - - // CDC Data - dif InterfaceDescriptor - in EndpointDescriptor - out EndpointDescriptor -} - -func NewCDCDescriptor(i IADDescriptor, c InterfaceDescriptor, - h CDCCSInterfaceDescriptor, - cm ACMFunctionalDescriptor, - fd CDCCSInterfaceDescriptor, - callm CMFunctionalDescriptor, - ci EndpointDescriptor, - di InterfaceDescriptor, - outp EndpointDescriptor, - inp EndpointDescriptor) CDCDescriptor { - return CDCDescriptor{iad: i, - cif: c, - header: h, - controlManagement: cm, - functionalDescriptor: fd, - callManagement: callm, - cifin: ci, - dif: di, - in: inp, - out: outp} -} - -const cdcSize = iadDescriptorSize + - interfaceDescriptorSize + - cdcCSInterfaceDescriptorSize + - acmFunctionalDescriptorSize + - cdcCSInterfaceDescriptorSize + - cmFunctionalDescriptorSize + - endpointDescriptorSize + - interfaceDescriptorSize + - endpointDescriptorSize + - endpointDescriptorSize - -// Bytes returns CDCDescriptor data. -func (d CDCDescriptor) Bytes() [cdcSize]byte { - var b [cdcSize]byte - offset := 0 - - iad := d.iad.Bytes() - copy(b[offset:], iad[:]) - offset += len(iad) - - cif := d.cif.Bytes() - copy(b[offset:], cif[:]) - offset += len(cif) - - header := d.header.Bytes() - copy(b[offset:], header[:]) - offset += len(header) - - controlManagement := d.controlManagement.Bytes() - copy(b[offset:], controlManagement[:]) - offset += len(controlManagement) - - functionalDescriptor := d.functionalDescriptor.Bytes() - copy(b[offset:], functionalDescriptor[:]) - offset += len(functionalDescriptor) - - callManagement := d.callManagement.Bytes() - copy(b[offset:], callManagement[:]) - offset += len(callManagement) - - cifin := d.cifin.Bytes() - copy(b[offset:], cifin[:]) - offset += len(cifin) - - dif := d.dif.Bytes() - copy(b[offset:], dif[:]) - offset += len(dif) - - out := d.out.Bytes() - copy(b[offset:], out[:]) - offset += len(out) - - in := d.in.Bytes() - copy(b[offset:], in[:]) - offset += len(in) - - return b -} - -// MSCDescriptor is not used yet. -type MSCDescriptor struct { - msc InterfaceDescriptor - in EndpointDescriptor - out EndpointDescriptor -} - const cdcLineInfoSize = 7 type cdcLineInfo struct { @@ -455,6 +64,8 @@ const ( usb_ENDPOINT_DESCRIPTOR_TYPE = 5 usb_DEVICE_QUALIFIER = 6 usb_OTHER_SPEED_CONFIGURATION = 7 + usb_SET_REPORT_TYPE = 33 + usb_HID_REPORT_TYPE = 34 usbEndpointOut = 0x00 usbEndpointIn = 0x80 @@ -474,6 +85,9 @@ const ( usb_GET_INTERFACE = 10 usb_SET_INTERFACE = 11 + // non standard requests + usb_SET_IDLE = 10 + usb_DEVICE_CLASS_COMMUNICATIONS = 0x02 usb_DEVICE_CLASS_HUMAN_INTERFACE = 0x03 usb_DEVICE_CLASS_STORAGE = 0x08 @@ -488,9 +102,12 @@ const ( usb_CDC_ACM_INTERFACE = 0 // CDC ACM usb_CDC_DATA_INTERFACE = 1 // CDC Data usb_CDC_FIRST_ENDPOINT = 1 - usb_CDC_ENDPOINT_ACM = 1 - usb_CDC_ENDPOINT_OUT = 2 - usb_CDC_ENDPOINT_IN = 3 + + // Endpoint + usb_CDC_ENDPOINT_ACM = 1 + usb_CDC_ENDPOINT_OUT = 2 + usb_CDC_ENDPOINT_IN = 3 + usb_HID_ENDPOINT_IN = 4 // bmRequestType usb_REQUEST_HOSTTODEVICE = 0x00 @@ -661,40 +278,43 @@ func (usbcdc *USBCDC) Receive(data byte) { func sendDescriptor(setup usbSetup) { switch setup.wValueH { case usb_CONFIGURATION_DESCRIPTOR_TYPE: - sendConfiguration(setup) + sendUSBPacket(0, usbDescriptor.Configuration, setup.wLength) return case usb_DEVICE_DESCRIPTOR_TYPE: // composite descriptor - dd := NewDeviceDescriptor(0xef, 0x02, 0x01, 64, usb_VID, usb_PID, 0x100, usb_IMANUFACTURER, usb_IPRODUCT, usb_ISERIAL, 1) - l := deviceDescriptorSize - if setup.wLength < deviceDescriptorSize { - l = int(setup.wLength) - } - buf := dd.Bytes() - sendUSBPacket(0, buf[:l]) + usbDescriptor.Configure(usb_VID, usb_PID) + sendUSBPacket(0, usbDescriptor.Device, setup.wLength) return case usb_STRING_DESCRIPTOR_TYPE: switch setup.wValueL { case 0: b := []byte{0x04, 0x03, 0x09, 0x04} - sendUSBPacket(0, b) + sendUSBPacket(0, b, setup.wLength) case usb_IPRODUCT: b := make([]byte, (len(usb_STRING_PRODUCT)<<1)+2) strToUTF16LEDescriptor(usb_STRING_PRODUCT, b) - sendUSBPacket(0, b) + sendUSBPacket(0, b, setup.wLength) case usb_IMANUFACTURER: b := make([]byte, (len(usb_STRING_MANUFACTURER)<<1)+2) strToUTF16LEDescriptor(usb_STRING_MANUFACTURER, b) - sendUSBPacket(0, b) + sendUSBPacket(0, b, setup.wLength) case usb_ISERIAL: // TODO: allow returning a product serial number sendZlp() } return + case usb_HID_REPORT_TYPE: + if h, ok := usbDescriptor.HID[setup.wIndex]; ok { + sendUSBPacket(0, h, setup.wLength) + return + } + case usb_DEVICE_QUALIFIER: + // skip + default: } // do not know how to handle this message, so return zero @@ -702,54 +322,17 @@ func sendDescriptor(setup usbSetup) { return } -// sendConfiguration creates and sends the configuration packet to the host. -func sendConfiguration(setup usbSetup) { - if setup.wLength == 9 { - sz := uint16(configDescriptorSize + cdcSize) - config := NewConfigDescriptor(sz, 2) - configBuf := config.Bytes() - sendUSBPacket(0, configBuf[:]) - } else { - iad := NewIADDescriptor(0, 2, usb_CDC_COMMUNICATION_INTERFACE_CLASS, usb_CDC_ABSTRACT_CONTROL_MODEL, 0) - - cif := NewInterfaceDescriptor(usb_CDC_ACM_INTERFACE, 1, usb_CDC_COMMUNICATION_INTERFACE_CLASS, usb_CDC_ABSTRACT_CONTROL_MODEL, 0) - - header := NewCDCCSInterfaceDescriptor(usb_CDC_HEADER, usb_CDC_V1_10&0xFF, (usb_CDC_V1_10>>8)&0x0FF) - - controlManagement := NewACMFunctionalDescriptor(usb_CDC_ABSTRACT_CONTROL_MANAGEMENT, 6) +// EnableHID enables HID. This function must be executed from the init(). +func EnableHID(callback func()) { + usbDescriptor = descriptorCDCHID + endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL, + (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn), + (usb_ENDPOINT_TYPE_BULK | usbEndpointOut), + (usb_ENDPOINT_TYPE_BULK | usbEndpointIn), + (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)} - functionalDescriptor := NewCDCCSInterfaceDescriptor(usb_CDC_UNION, usb_CDC_ACM_INTERFACE, usb_CDC_DATA_INTERFACE) - - callManagement := NewCMFunctionalDescriptor(usb_CDC_CALL_MANAGEMENT, 1, 1) - - cifin := NewEndpointDescriptor((usb_CDC_ENDPOINT_ACM | usbEndpointIn), usb_ENDPOINT_TYPE_INTERRUPT, 0x10, 0x10) - - dif := NewInterfaceDescriptor(usb_CDC_DATA_INTERFACE, 2, usb_CDC_DATA_INTERFACE_CLASS, 0, 0) - - out := NewEndpointDescriptor((usb_CDC_ENDPOINT_OUT | usbEndpointOut), usb_ENDPOINT_TYPE_BULK, usbEndpointPacketSize, 0) - - in := NewEndpointDescriptor((usb_CDC_ENDPOINT_IN | usbEndpointIn), usb_ENDPOINT_TYPE_BULK, usbEndpointPacketSize, 0) - - cdc := NewCDCDescriptor(iad, - cif, - header, - controlManagement, - functionalDescriptor, - callManagement, - cifin, - dif, - out, - in) - - sz := uint16(configDescriptorSize + cdcSize) - config := NewConfigDescriptor(sz, 2) - - configBuf := config.Bytes() - cdcBuf := cdc.Bytes() - var buf [configDescriptorSize + cdcSize]byte - copy(buf[0:], configBuf[:]) - copy(buf[configDescriptorSize:], cdcBuf[:]) - - sendUSBPacket(0, buf[:]) - } + hidCallback = callback } + +// hidCallback is a variable that holds the callback when using HID. +var hidCallback func() diff --git a/src/machine/usb/hid/buffer.go b/src/machine/usb/hid/buffer.go new file mode 100644 index 000000000..2674bbde9 --- /dev/null +++ b/src/machine/usb/hid/buffer.go @@ -0,0 +1,52 @@ +package hid + +import ( + "runtime/volatile" +) + +const bufferSize = 128 + +// RingBuffer is ring buffer implementation inspired by post at +// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php +type RingBuffer struct { + rxbuffer [bufferSize][9]byte + head volatile.Register8 + tail volatile.Register8 +} + +// NewRingBuffer returns a new ring buffer. +func NewRingBuffer() *RingBuffer { + return &RingBuffer{} +} + +// Used returns how many bytes in buffer have been used. +func (rb *RingBuffer) Used() uint8 { + return uint8(rb.head.Get() - rb.tail.Get()) +} + +// Put stores a byte in the buffer. If the buffer is already +// full, the method will return false. +func (rb *RingBuffer) Put(val []byte) bool { + if rb.Used() != bufferSize { + rb.head.Set(rb.head.Get() + 1) + copy(rb.rxbuffer[rb.head.Get()%bufferSize][:], val) + return true + } + return false +} + +// Get returns a byte from the buffer. If the buffer is empty, +// the method will return a false as the second value. +func (rb *RingBuffer) Get() ([]byte, bool) { + if rb.Used() != 0 { + rb.tail.Set(rb.tail.Get() + 1) + return rb.rxbuffer[rb.tail.Get()%bufferSize][:], true + } + return nil, false +} + +// Clear resets the head and tail pointer to zero. +func (rb *RingBuffer) Clear() { + rb.head.Set(0) + rb.tail.Set(0) +} diff --git a/src/machine/usb/hid/hid.go b/src/machine/usb/hid/hid.go new file mode 100644 index 000000000..fd9317511 --- /dev/null +++ b/src/machine/usb/hid/hid.go @@ -0,0 +1,51 @@ +package hid + +import ( + "errors" + "machine" +) + +// from usb-hid.go +var ( + ErrHIDInvalidPort = errors.New("invalid USB port") + ErrHIDInvalidCore = errors.New("invalid USB core") + ErrHIDReportTransfer = errors.New("failed to transfer HID report") +) + +const ( + hidEndpoint = 4 +) + +type hidDevicer interface { + Callback() bool +} + +var devices [5]hidDevicer +var size int + +// SetCallbackHandler sets the callback. Only the first time it is called, it +// calls machine.EnableHID for USB configuration +func SetCallbackHandler(d hidDevicer) { + if size == 0 { + machine.EnableHID(callback) + } + + devices[size] = d + size++ +} + +func callback() { + for _, d := range devices { + if d == nil { + continue + } + if done := d.Callback(); done { + return + } + } +} + +// SendUSBPacket sends a HIDPacket. +func SendUSBPacket(b []byte) { + machine.SendUSBHIDPacket(hidEndpoint, b) +} diff --git a/src/machine/usb/hid/keyboard/keyboard.go b/src/machine/usb/hid/keyboard/keyboard.go new file mode 100644 index 000000000..1f5643385 --- /dev/null +++ b/src/machine/usb/hid/keyboard/keyboard.go @@ -0,0 +1,478 @@ +package keyboard + +import ( + "errors" + "machine/usb/hid" +) + +// from usb-hid-keyboard.go +var ( + ErrInvalidCodepoint = errors.New("invalid Unicode codepoint") + ErrInvalidKeycode = errors.New("invalid keyboard keycode") + ErrInvalidUTF8 = errors.New("invalid UTF-8 encoding") + ErrKeypressMaximum = errors.New("maximum keypresses exceeded") +) + +var Keyboard *keyboard + +// Keyboard represents a USB HID keyboard device with support for international +// layouts and various control, system, multimedia, and consumer keycodes. +// +// Keyboard implements the io.Writer interface that translates UTF-8 encoded +// byte strings into sequences of keypress events. +type keyboard struct { + // led holds the current state of all keyboard LEDs: + // 1=NumLock 2=CapsLock 4=ScrollLock 8=Compose 16=Kana + led uint8 + + // mod holds the current state of all keyboard modifier keys: + // 1=LeftCtrl 2=LeftShift 4=LeftAlt 8=LeftGUI + // 16=RightCtrl 32=RightShift 64=RightAlt 128=RightGUI + mod uint8 + + // key holds a list of all keyboard keys currently pressed. + key [hidKeyboardKeyCount]uint8 + con [hidKeyboardConCount]uint16 + sys [hidKeyboardSysCount]uint8 + + // decode holds the current state of the UTF-8 decoder. + decode decodeState + + // wideChar holds high bits for the UTF-8 decoder. + wideChar uint16 + + buf *hid.RingBuffer +} + +// decodeState represents a state in the UTF-8 decode state machine. +type decodeState uint8 + +// Constant enumerated values of type decodeState. +const ( + decodeReset decodeState = iota + decodeByte1 + decodeByte2 + decodeByte3 +) + +func init() { + if Keyboard == nil { + Keyboard = newKeyboard() + hid.SetCallbackHandler(Keyboard) + } +} + +// New returns hid-keybord. +func New() *keyboard { + return Keyboard +} + +func newKeyboard() *keyboard { + return &keyboard{ + buf: hid.NewRingBuffer(), + } +} + +func (kb *keyboard) Callback() bool { + if b, ok := kb.buf.Get(); ok { + hid.SendUSBPacket(b) + return true + } + return false +} + +func (kb *keyboard) ready() bool { + return true +} + +// Write transmits press-and-release key sequences for each Keycode translated +// from the given UTF-8 byte string. Write implements the io.Writer interface +// and conforms to all documented conventions for arguments and return values. +func (kb *keyboard) Write(b []byte) (n int, err error) { + for _, c := range b { + if err = kb.WriteByte(c); nil != err { + break + } + n += 1 + } + return +} + +// WriteByte processes a single byte from a UTF-8 byte string. This method is a +// stateful method with respect to the receiver Keyboard, meaning that its exact +// behavior will depend on the current state of its UTF-8 decode state machine: +// +// (a) If the given byte is a valid ASCII encoding (0-127), then a keypress +// sequence is immediately transmitted for the respective Keycode. +// +// (b) If the given byte represents the final byte in a multi-byte codepoint, +// then a keypress sequence is immediately transmitted by translating the +// multi-byte codepoint to its respective Keycode. +// +// (c) If the given byte appears to represent high bits for a multi-byte +// codepoint, then the bits are copied to the receiver's internal state +// machine buffer for use by a subsequent call to WriteByte() (or Write()) +// that completes the codepoint. +// +// (d) If the given byte is out of range, or contains illegal bits for the +// current state of the UTF-8 decoder, then the UTF-8 decode state machine +// is reset to its initial state. +// +// In cases (c) and (d), a keypress sequence is not generated and no data is +// transmitted. In case (c), additional bytes must be received via WriteByte() +// (or Write()) to complete or discard the current codepoint. +func (kb *keyboard) WriteByte(b byte) error { + switch { + case b < 0x80: + // 1-byte encoding (0x00-0x7F) + kb.decode = decodeByte1 + return kb.write(uint16(b)) + + case b < 0xC0: + // 2nd, 3rd, or 4th byte (0x80-0xBF) + b = Keycode(b).key() + switch kb.decode { + case decodeByte2: + kb.decode = decodeByte1 + return kb.write(kb.wideChar | uint16(b)) + case decodeByte3: + kb.decode = decodeByte2 + kb.wideChar |= uint16(b) << 6 + } + + case b < 0xE0: + // 2-byte encoding (0xC2-0xDF), or illegal byte 2 (0xC0-0xC1) + kb.decode = decodeByte2 + kb.wideChar = uint16(b&0x1F) << 6 + + case b < 0xF0: + // 3-byte encoding (0xE0-0xEF) + kb.decode = decodeByte3 + kb.wideChar = uint16(b&0x0F) << 12 + + default: + // 4-byte encoding unsupported (0xF0-0xF4), or illegal byte 4 (0xF5-0xFF) + kb.decode = decodeReset + return ErrInvalidUTF8 + } + return nil +} + +func (kb *keyboard) write(p uint16) error { + c := keycode(p) + if 0 == c { + return ErrInvalidCodepoint + } + if d := deadkey(c); 0 != d { + if err := kb.writeKeycode(d); nil != err { + return err + } + } + return kb.writeKeycode(c) +} + +func (kb *keyboard) writeKeycode(c Keycode) error { + var b [9]byte + b[0] = 0x02 + b[1] = c.mod() + b[2] = 0 + b[3] = c.key() + b[4] = 0 + b[5] = 0 + b[6] = 0 + b[7] = 0 + b[8] = 0 + if !kb.sendKey(false, b[:]) { + return hid.ErrHIDReportTransfer + } + + b[1] = 0 + b[3] = 0 + if !kb.sendKey(false, b[:]) { + return hid.ErrHIDReportTransfer + } + return nil +} + +// Press transmits a press-and-release sequence for the given Keycode, which +// simulates a discrete keypress event. +// +// The following values of Keycode are supported: +// +// 0x0020 - 0x007F ASCII (U+0020 to U+007F) [USES LAYOUT] +// 0x0080 - 0xC1FF Unicode (U+0080 to U+C1FF) [USES LAYOUT] +// 0xC200 - 0xDFFF UTF-8 packed (U+0080 to U+07FF) [USES LAYOUT] +// 0xE000 - 0xE0FF Modifier key (bitmap, 8 keys, Shift/Ctrl/Alt/GUI) +// 0xE200 - 0xE2FF System key (HID usage code, page 1) +// 0xE400 - 0xE7FF Media/Consumer key (HID usage code, page 12) +// 0xF000 - 0xFFFF Normal key (HID usage code, page 7) +func (kb *keyboard) Press(c Keycode) error { + if err := kb.Down(c); nil != err { + return err + } + return kb.Up(c) +} + +func (kb *keyboard) sendKey(consumer bool, b []byte) bool { + kb.buf.Put(b) + return true +} + +func (kb *keyboard) keyboardSendKeys(consumer bool) bool { + var b [9]byte + b[0] = 0x02 + b[1] = kb.mod + b[2] = 0x02 + b[3] = kb.key[0] + b[4] = kb.key[1] + b[5] = kb.key[2] + b[6] = kb.key[3] + b[7] = kb.key[4] + b[8] = kb.key[5] + return kb.sendKey(consumer, b[:]) +} + +// Down transmits a key-down event for the given Keycode. +// +// The host will interpret the key as being held down continuously until a +// corresponding key-up event is transmitted, e.g., via method Up(). +// +// See godoc comment on method Press() for details on what input is accepted and +// how it is interpreted. +func (kb *keyboard) Down(c Keycode) error { + var res uint8 + msb := c >> 8 + if msb >= 0xC2 { + if msb < 0xE0 { + c = ((msb & 0x1F) << 6) | Keycode(c.key()) + } else { + switch msb { + case 0xF0: + return kb.down(uint8(c), 0) + + case 0xE0: + return kb.down(0, uint8(c)) + + case 0xE2: + return kb.downSys(uint8(c)) + + default: + if 0xE4 <= msb && msb <= 0xE7 { + return kb.downCon(uint16(c & 0x03FF)) + } + return ErrInvalidKeycode + } + } + } + c = keycode(uint16(c)) + if 0 == c { + return ErrInvalidCodepoint + } + if d := deadkey(c); 0 != d { + res = kb.mod + if 0 != res { + kb.mod = 0 + kb.keyboardSendKeys(false) + } + kb.down(d.key(), d.mod()) + kb.up(d.key(), d.mod()) + } + return kb.down(c.key(), c.mod()|res) +} + +func (kb *keyboard) down(key uint8, mod uint8) error { + send := false + if 0 != mod { + if kb.mod&mod != mod { + kb.mod |= mod + send = true + } + } + if 0 != key { + for _, k := range kb.key { + if k == key { + goto end + } + } + for i, k := range kb.key { + if 0 == k { + kb.key[i] = key + send = true + goto end + } + } + return ErrKeypressMaximum + } +end: + if send { + if !kb.keyboardSendKeys(false) { + return hid.ErrHIDReportTransfer + } + } + return nil +} + +func (kb *keyboard) downCon(key uint16) error { + if 0 == key { + return ErrInvalidKeycode + } + for _, k := range kb.con { + if key == k { + return nil // already pressed + } + } + for i, k := range kb.con { + if 0 == k { + kb.con[i] = key + if !kb.keyboardSendKeys(true) { + return hid.ErrHIDReportTransfer + } + return nil + } + } + return ErrKeypressMaximum +} + +func (kb *keyboard) downSys(key uint8) error { + if 0 == key { + return ErrInvalidKeycode + } + for _, k := range kb.sys { + if key == k { + return nil // already pressed + } + } + for i, k := range kb.sys { + if 0 == k { + kb.sys[i] = key + if !kb.keyboardSendKeys(true) { + return hid.ErrHIDReportTransfer + } + return nil + } + } + return ErrKeypressMaximum +} + +// Up transmits a key-up event for the given Keycode. +// +// See godoc comment on method Press() for details on what input is accepted and +// how it is interpreted. +func (kb *keyboard) Up(c Keycode) error { + msb := c >> 8 + if msb >= 0xC2 { + if msb < 0xE0 { + c = ((msb & 0x1F) << 6) | Keycode(c.key()) + } else { + switch msb { + case 0xF0: + return kb.up(uint8(c), 0) + + case 0xE0: + return kb.up(0, uint8(c)) + + case 0xE2: + return kb.upSys(uint8(c)) + + default: + if 0xE4 <= msb && msb <= 0xE7 { + return kb.upCon(uint16(c & 0x03FF)) + } + return ErrInvalidKeycode + } + } + } + c = keycode(uint16(c)) + if 0 == c { + return ErrInvalidCodepoint + } + return kb.up(c.key(), c.mod()) +} + +// Release transmits a key-up event for all keyboard keys currently pressed as +// if the user removed his/her hands from the keyboard entirely. +func (kb *keyboard) Release() error { + + bits := uint16(kb.mod) + kb.mod = 0 + for i, k := range kb.key { + bits |= uint16(k) + kb.key[i] = 0 + } + if 0 != bits { + if !kb.keyboardSendKeys(false) { + return hid.ErrHIDReportTransfer + } + } + bits = 0 + for i, k := range kb.con { + bits |= k + kb.con[i] = 0 + } + for i, k := range kb.sys { + bits |= uint16(k) + kb.sys[i] = 0 + } + if 0 != bits { + if !kb.keyboardSendKeys(true) { + return hid.ErrHIDReportTransfer + } + } + return nil +} + +func (kb *keyboard) up(key uint8, mod uint8) error { + send := false + if 0 != mod { + if kb.mod&mod != 0 { + kb.mod &^= mod + send = true + } + } + if 0 != key { + for i, k := range kb.key { + if key == k { + kb.key[i] = 0 + send = true + } + } + } + if send { + if !kb.keyboardSendKeys(false) { + return hid.ErrHIDReportTransfer + } + } + return nil +} + +func (kb *keyboard) upCon(key uint16) error { + if 0 == key { + return ErrInvalidKeycode + } + for i, k := range kb.con { + if key == k { + kb.con[i] = 0 + if !kb.keyboardSendKeys(true) { + return hid.ErrHIDReportTransfer + } + return nil + } + } + return nil +} + +func (kb *keyboard) upSys(key uint8) error { + if 0 == key { + return ErrInvalidKeycode + } + for i, k := range kb.sys { + if key == k { + kb.sys[i] = 0 + if !kb.keyboardSendKeys(true) { + return hid.ErrHIDReportTransfer + } + return nil + } + } + return nil +} diff --git a/src/machine/usb/hid/keyboard/keycode.go b/src/machine/usb/hid/keyboard/keycode.go new file mode 100644 index 000000000..c9e3b9350 --- /dev/null +++ b/src/machine/usb/hid/keyboard/keycode.go @@ -0,0 +1,532 @@ +package keyboard + +// Keycode is a package-defined bitmap used to encode the value of a given key. +type Keycode uint16 + +// keycode returns the given Unicode codepoint translated to a Keycode sequence. +// Unicode codepoints greater than U+FFFF are unsupported. +//go:inline +func keycode(p uint16) Keycode { + if p < 0x80 { + return ascii[p] + } else if p >= 0xA0 && p < 0x0100 { + return iso88591[p-0xA0] + } else if uint16(UNICODE20AC) == p { + return UNICODE20AC.mask() + } + return 0 +} + +//go:inline +func deadkey(c Keycode) Keycode { + switch c & deadkeysMask { + case acuteAccentBits: + return deadkeyAcuteAccent + case circumflexBits: + return deadkeyCircumflex + case diaeresisBits: + return deadkeyDiaeresis + case graveAccentBits: + return deadkeyGraveAccent + case tildeBits: + return deadkeyTilde + } + return 0 +} + +//go:inline +func (c Keycode) mask() Keycode { return c & keycodeMask } + +//go:inline +func (c Keycode) key() uint8 { return uint8(c & keyMask) } + +//go:inline +func (c Keycode) mod() uint8 { + var m Keycode + if 0 != c&shiftMask { + m |= KeyModifierShift + } + if 0 != c&altgrMask { + m |= KeyModifierRightAlt + } + return uint8(m) +} + +//go:inline +func (c Keycode) Shift() Keycode { return c | KeyModifierShift } + +const ( + hidKeyboardKeyCount = 6 // Max number of simultaneous keypresses + hidKeyboardSysCount = 3 + hidKeyboardConCount = 4 +) + +// Keycodes common to all Keyboard layouts +const ( + KeyModifierCtrl Keycode = 0x01 | 0xE000 + KeyModifierShift Keycode = 0x02 | 0xE000 + KeyModifierAlt Keycode = 0x04 | 0xE000 + KeyModifierGUI Keycode = 0x08 | 0xE000 + KeyModifierLeftCtrl Keycode = 0x01 | 0xE000 + KeyModifierLeftShift Keycode = 0x02 | 0xE000 + KeyModifierLeftAlt Keycode = 0x04 | 0xE000 + KeyModifierLeftGUI Keycode = 0x08 | 0xE000 + KeyModifierRightCtrl Keycode = 0x10 | 0xE000 + KeyModifierRightShift Keycode = 0x20 | 0xE000 + KeyModifierRightAlt Keycode = 0x40 | 0xE000 + KeyModifierRightGUI Keycode = 0x80 | 0xE000 + + KeySystemPowerDown Keycode = 0x81 | 0xE200 + KeySystemSleep Keycode = 0x82 | 0xE200 + KeySystemWakeUp Keycode = 0x83 | 0xE200 + + KeyMediaPlay Keycode = 0xB0 | 0xE400 + KeyMediaPause Keycode = 0xB1 | 0xE400 + KeyMediaRecord Keycode = 0xB2 | 0xE400 + KeyMediaFastForward Keycode = 0xB3 | 0xE400 + KeyMediaRewind Keycode = 0xB4 | 0xE400 + KeyMediaNextTrack Keycode = 0xB5 | 0xE400 + KeyMediaPrevTrack Keycode = 0xB6 | 0xE400 + KeyMediaStop Keycode = 0xB7 | 0xE400 + KeyMediaEject Keycode = 0xB8 | 0xE400 + KeyMediaRandomPlay Keycode = 0xB9 | 0xE400 + KeyMediaPlayPause Keycode = 0xCD | 0xE400 + KeyMediaPlaySkip Keycode = 0xCE | 0xE400 + KeyMediaMute Keycode = 0xE2 | 0xE400 + KeyMediaVolumeInc Keycode = 0xE9 | 0xE400 + KeyMediaVolumeDec Keycode = 0xEA | 0xE400 + + KeyA Keycode = 4 | 0xF000 + KeyB Keycode = 5 | 0xF000 + KeyC Keycode = 6 | 0xF000 + KeyD Keycode = 7 | 0xF000 + KeyE Keycode = 8 | 0xF000 + KeyF Keycode = 9 | 0xF000 + KeyG Keycode = 10 | 0xF000 + KeyH Keycode = 11 | 0xF000 + KeyI Keycode = 12 | 0xF000 + KeyJ Keycode = 13 | 0xF000 + KeyK Keycode = 14 | 0xF000 + KeyL Keycode = 15 | 0xF000 + KeyM Keycode = 16 | 0xF000 + KeyN Keycode = 17 | 0xF000 + KeyO Keycode = 18 | 0xF000 + KeyP Keycode = 19 | 0xF000 + KeyQ Keycode = 20 | 0xF000 + KeyR Keycode = 21 | 0xF000 + KeyS Keycode = 22 | 0xF000 + KeyT Keycode = 23 | 0xF000 + KeyU Keycode = 24 | 0xF000 + KeyV Keycode = 25 | 0xF000 + KeyW Keycode = 26 | 0xF000 + KeyX Keycode = 27 | 0xF000 + KeyY Keycode = 28 | 0xF000 + KeyZ Keycode = 29 | 0xF000 + Key1 Keycode = 30 | 0xF000 + Key2 Keycode = 31 | 0xF000 + Key3 Keycode = 32 | 0xF000 + Key4 Keycode = 33 | 0xF000 + Key5 Keycode = 34 | 0xF000 + Key6 Keycode = 35 | 0xF000 + Key7 Keycode = 36 | 0xF000 + Key8 Keycode = 37 | 0xF000 + Key9 Keycode = 38 | 0xF000 + Key0 Keycode = 39 | 0xF000 + KeyEnter Keycode = 40 | 0xF000 + KeyEsc Keycode = 41 | 0xF000 + KeyBackspace Keycode = 42 | 0xF000 + KeyTab Keycode = 43 | 0xF000 + KeySpace Keycode = 44 | 0xF000 + KeyMinus Keycode = 45 | 0xF000 + KeyEqual Keycode = 46 | 0xF000 + KeyLeftBrace Keycode = 47 | 0xF000 + KeyRightBrace Keycode = 48 | 0xF000 + KeyBackslash Keycode = 49 | 0xF000 + KeyNonUsNum Keycode = 50 | 0xF000 + KeySemicolon Keycode = 51 | 0xF000 + KeyQuote Keycode = 52 | 0xF000 + KeyTilde Keycode = 53 | 0xF000 + KeyComma Keycode = 54 | 0xF000 + KeyPeriod Keycode = 55 | 0xF000 + KeySlash Keycode = 56 | 0xF000 + KeyCapsLock Keycode = 57 | 0xF000 + KeyF1 Keycode = 58 | 0xF000 + KeyF2 Keycode = 59 | 0xF000 + KeyF3 Keycode = 60 | 0xF000 + KeyF4 Keycode = 61 | 0xF000 + KeyF5 Keycode = 62 | 0xF000 + KeyF6 Keycode = 63 | 0xF000 + KeyF7 Keycode = 64 | 0xF000 + KeyF8 Keycode = 65 | 0xF000 + KeyF9 Keycode = 66 | 0xF000 + KeyF10 Keycode = 67 | 0xF000 + KeyF11 Keycode = 68 | 0xF000 + KeyF12 Keycode = 69 | 0xF000 + KeyPrintscreen Keycode = 70 | 0xF000 + KeyScrollLock Keycode = 71 | 0xF000 + KeyPause Keycode = 72 | 0xF000 + KeyInsert Keycode = 73 | 0xF000 + KeyHome Keycode = 74 | 0xF000 + KeyPageUp Keycode = 75 | 0xF000 + KeyDelete Keycode = 76 | 0xF000 + KeyEnd Keycode = 77 | 0xF000 + KeyPageDown Keycode = 78 | 0xF000 + KeyRight Keycode = 79 | 0xF000 + KeyLeft Keycode = 80 | 0xF000 + KeyDown Keycode = 81 | 0xF000 + KeyUp Keycode = 82 | 0xF000 + KeyNumLock Keycode = 83 | 0xF000 + KeypadSlash Keycode = 84 | 0xF000 + KeypadAsterisk Keycode = 85 | 0xF000 + KeypadMinus Keycode = 86 | 0xF000 + KeypadPlus Keycode = 87 | 0xF000 + KeypadEnter Keycode = 88 | 0xF000 + Keypad1 Keycode = 89 | 0xF000 + Keypad2 Keycode = 90 | 0xF000 + Keypad3 Keycode = 91 | 0xF000 + Keypad4 Keycode = 92 | 0xF000 + Keypad5 Keycode = 93 | 0xF000 + Keypad6 Keycode = 94 | 0xF000 + Keypad7 Keycode = 95 | 0xF000 + Keypad8 Keycode = 96 | 0xF000 + Keypad9 Keycode = 97 | 0xF000 + Keypad0 Keycode = 98 | 0xF000 + KeypadPeriod Keycode = 99 | 0xF000 + KeyNonUSBS Keycode = 100 | 0xF000 + KeyMenu Keycode = 101 | 0xF000 + KeyF13 Keycode = 104 | 0xF000 + KeyF14 Keycode = 105 | 0xF000 + KeyF15 Keycode = 106 | 0xF000 + KeyF16 Keycode = 107 | 0xF000 + KeyF17 Keycode = 108 | 0xF000 + KeyF18 Keycode = 109 | 0xF000 + KeyF19 Keycode = 110 | 0xF000 + KeyF20 Keycode = 111 | 0xF000 + KeyF21 Keycode = 112 | 0xF000 + KeyF22 Keycode = 113 | 0xF000 + KeyF23 Keycode = 114 | 0xF000 + KeyF24 Keycode = 115 | 0xF000 + + KeyUpArrow Keycode = KeyUp + KeyDownArrow Keycode = KeyDown + KeyLeftArrow Keycode = KeyLeft + KeyRightArrow Keycode = KeyRight + KeyReturn Keycode = KeyEnter + KeyLeftCtrl Keycode = KeyModifierLeftCtrl + KeyLeftShift Keycode = KeyModifierLeftShift + KeyLeftAlt Keycode = KeyModifierLeftAlt + KeyLeftGUI Keycode = KeyModifierLeftGUI + KeyRightCtrl Keycode = KeyModifierRightCtrl + KeyRightShift Keycode = KeyModifierRightShift + KeyRightAlt Keycode = KeyModifierRightAlt + KeyRightGUI Keycode = KeyModifierRightGUI +) + +// Keycodes for layout US English (0x0904) +const ( + keycodeMask Keycode = 0x07FF + keyMask Keycode = 0x003F + + shiftMask Keycode = 0x0040 + altgrMask Keycode = 0x0080 + deadkeysMask Keycode = 0x0700 + circumflexBits Keycode = 0x0100 + acuteAccentBits Keycode = 0x0200 + graveAccentBits Keycode = 0x0300 + tildeBits Keycode = 0x0400 + diaeresisBits Keycode = 0x0500 + deadkeyCircumflex Keycode = Key6 | shiftMask + deadkeyAcuteAccent Keycode = KeyQuote + deadkeyGraveAccent Keycode = KeyTilde + deadkeyTilde Keycode = KeyTilde | shiftMask + deadkeyDiaeresis Keycode = KeyQuote | shiftMask + + ASCII00 Keycode = 0 // 0 NUL + ASCII01 Keycode = 0 // 1 SOH + ASCII02 Keycode = 0 // 2 STX + ASCII03 Keycode = 0 // 3 ETX + ASCII04 Keycode = 0 // 4 EOT + ASCII05 Keycode = 0 // 5 ENQ + ASCII06 Keycode = 0 // 6 ACK + ASCII07 Keycode = 0 // 7 BEL + ASCII08 Keycode = KeyBackspace // 8 BS + ASCII09 Keycode = KeyTab // 9 TAB + ASCII0A Keycode = KeyEnter // 10 LF + ASCII0B Keycode = 0 // 11 VT + ASCII0C Keycode = 0 // 12 FF + ASCII0D Keycode = 0 // 13 CR + ASCII0E Keycode = 0 // 14 SO + ASCII0F Keycode = 0 // 15 SI + ASCII10 Keycode = 0 // 16 DEL + ASCII11 Keycode = 0 // 17 DC1 + ASCII12 Keycode = 0 // 18 DC2 + ASCII13 Keycode = 0 // 19 DC3 + ASCII14 Keycode = 0 // 20 DC4 + ASCII15 Keycode = 0 // 21 NAK + ASCII16 Keycode = 0 // 22 SYN + ASCII17 Keycode = 0 // 23 ETB + ASCII18 Keycode = 0 // 24 CAN + ASCII19 Keycode = 0 // 25 EM + ASCII1A Keycode = 0 // 26 SUB + ASCII1B Keycode = 0 // 27 ESC + ASCII1C Keycode = 0 // 28 FS + ASCII1D Keycode = 0 // 29 GS + ASCII1E Keycode = 0 // 30 RS + ASCII1F Keycode = 0 // 31 US + + ASCII20 Keycode = KeySpace // 32 SPACE + ASCII21 Keycode = Key1 | shiftMask // 33 ! + ASCII22 Keycode = diaeresisBits | KeySpace // 34 " + ASCII23 Keycode = Key3 | shiftMask // 35 # + ASCII24 Keycode = Key4 | shiftMask // 36 $ + ASCII25 Keycode = Key5 | shiftMask // 37 % + ASCII26 Keycode = Key7 | shiftMask // 38 & + ASCII27 Keycode = acuteAccentBits | KeySpace // 39 ' + ASCII28 Keycode = Key9 | shiftMask // 40 ( + ASCII29 Keycode = Key0 | shiftMask // 41 ) + ASCII2A Keycode = Key8 | shiftMask // 42 * + ASCII2B Keycode = KeyEqual | shiftMask // 43 + + ASCII2C Keycode = KeyComma // 44 , + ASCII2D Keycode = KeyMinus // 45 - + ASCII2E Keycode = KeyPeriod // 46 . + ASCII2F Keycode = KeySlash // 47 / + ASCII30 Keycode = Key0 // 48 0 + ASCII31 Keycode = Key1 // 49 1 + ASCII32 Keycode = Key2 // 50 2 + ASCII33 Keycode = Key3 // 51 3 + ASCII34 Keycode = Key4 // 52 4 + ASCII35 Keycode = Key5 // 53 5 + ASCII36 Keycode = Key6 // 54 6 + ASCII37 Keycode = Key7 // 55 7 + ASCII38 Keycode = Key8 // 55 8 + ASCII39 Keycode = Key9 // 57 9 + ASCII3A Keycode = KeySemicolon | shiftMask // 58 : + ASCII3B Keycode = KeySemicolon // 59 ; + ASCII3C Keycode = KeyComma | shiftMask // 60 < + ASCII3D Keycode = KeyEqual // 61 = + ASCII3E Keycode = KeyPeriod | shiftMask // 62 > + ASCII3F Keycode = KeySlash | shiftMask // 63 ? + ASCII40 Keycode = Key2 | shiftMask // 64 @ + ASCII41 Keycode = KeyA | shiftMask // 65 A + ASCII42 Keycode = KeyB | shiftMask // 66 B + ASCII43 Keycode = KeyC | shiftMask // 67 C + ASCII44 Keycode = KeyD | shiftMask // 68 D + ASCII45 Keycode = KeyE | shiftMask // 69 E + ASCII46 Keycode = KeyF | shiftMask // 70 F + ASCII47 Keycode = KeyG | shiftMask // 71 G + ASCII48 Keycode = KeyH | shiftMask // 72 H + ASCII49 Keycode = KeyI | shiftMask // 73 I + ASCII4A Keycode = KeyJ | shiftMask // 74 J + ASCII4B Keycode = KeyK | shiftMask // 75 K + ASCII4C Keycode = KeyL | shiftMask // 76 L + ASCII4D Keycode = KeyM | shiftMask // 77 M + ASCII4E Keycode = KeyN | shiftMask // 78 N + ASCII4F Keycode = KeyO | shiftMask // 79 O + ASCII50 Keycode = KeyP | shiftMask // 80 P + ASCII51 Keycode = KeyQ | shiftMask // 81 Q + ASCII52 Keycode = KeyR | shiftMask // 82 R + ASCII53 Keycode = KeyS | shiftMask // 83 S + ASCII54 Keycode = KeyT | shiftMask // 84 T + ASCII55 Keycode = KeyU | shiftMask // 85 U + ASCII56 Keycode = KeyV | shiftMask // 86 V + ASCII57 Keycode = KeyW | shiftMask // 87 W + ASCII58 Keycode = KeyX | shiftMask // 88 X + ASCII59 Keycode = KeyY | shiftMask // 89 Y + ASCII5A Keycode = KeyZ | shiftMask // 90 Z + ASCII5B Keycode = KeyLeftBrace // 91 [ + ASCII5C Keycode = KeyBackslash // 92 \ + ASCII5D Keycode = KeyRightBrace // 93 ] + ASCII5E Keycode = circumflexBits | KeySpace // 94 ^ + ASCII5F Keycode = KeyMinus | shiftMask // 95 + ASCII60 Keycode = graveAccentBits | KeySpace // 96 ` + ASCII61 Keycode = KeyA // 97 a + ASCII62 Keycode = KeyB // 98 b + ASCII63 Keycode = KeyC // 99 c + ASCII64 Keycode = KeyD // 100 d + ASCII65 Keycode = KeyE // 101 e + ASCII66 Keycode = KeyF // 102 f + ASCII67 Keycode = KeyG // 103 g + ASCII68 Keycode = KeyH // 104 h + ASCII69 Keycode = KeyI // 105 i + ASCII6A Keycode = KeyJ // 106 j + ASCII6B Keycode = KeyK // 107 k + ASCII6C Keycode = KeyL // 108 l + ASCII6D Keycode = KeyM // 109 m + ASCII6E Keycode = KeyN // 110 n + ASCII6F Keycode = KeyO // 111 o + ASCII70 Keycode = KeyP // 112 p + ASCII71 Keycode = KeyQ // 113 q + ASCII72 Keycode = KeyR // 114 r + ASCII73 Keycode = KeyS // 115 s + ASCII74 Keycode = KeyT // 116 t + ASCII75 Keycode = KeyU // 117 u + ASCII76 Keycode = KeyV // 118 v + ASCII77 Keycode = KeyW // 119 w + ASCII78 Keycode = KeyX // 120 x + ASCII79 Keycode = KeyY // 121 y + ASCII7A Keycode = KeyZ // 122 z + ASCII7B Keycode = KeyLeftBrace | shiftMask // 123 { + ASCII7C Keycode = KeyBackslash | shiftMask // 124 | + ASCII7D Keycode = KeyRightBrace | shiftMask // 125 } + ASCII7E Keycode = tildeBits | KeySpace // 126 ~ + ASCII7F Keycode = KeyBackspace // 127 DEL + ISO88591A0 Keycode = KeySpace // 160 Nonbreakng Space + ISO88591A1 Keycode = Key1 | altgrMask // 161 ¡ Inverted Exclamation + ISO88591A2 Keycode = KeyC | altgrMask | shiftMask // 162 ¢ Cent SIGN + ISO88591A3 Keycode = Key4 | altgrMask | shiftMask // 163 £ Pound Sign + ISO88591A4 Keycode = Key4 | altgrMask // 164 ¤ Currency or Euro Sign + ISO88591A5 Keycode = KeyMinus | altgrMask // 165 ¥ YEN SIGN + ISO88591A6 Keycode = KeyBackslash | altgrMask | shiftMask // 166 ¦ BROKEN BAR ?? + ISO88591A7 Keycode = KeyS | altgrMask | shiftMask // 167 § SECTION SIGN + ISO88591A8 Keycode = KeyQuote | altgrMask | shiftMask // 168 ¨ DIAERESIS + ISO88591A9 Keycode = KeyC | altgrMask // 169 © COPYRIGHT SIGN + ISO88591AA Keycode = 0 // 170 ª FEMININE ORDINAL + ISO88591AB Keycode = KeyLeftBrace | altgrMask // 171 « LEFT DOUBLE ANGLE QUOTE + ISO88591AC Keycode = KeyBackslash | altgrMask // 172 ¬ NOT SIGN ?? + ISO88591AD Keycode = 0 // 173 SOFT HYPHEN + ISO88591AE Keycode = KeyR | altgrMask // 174 ® REGISTERED SIGN + ISO88591AF Keycode = 0 // 175 ¯ MACRON + ISO88591B0 Keycode = KeySemicolon | altgrMask | shiftMask // 176 ° DEGREE SIGN + ISO88591B1 Keycode = 0 // 177 ± PLUS-MINUS SIGN + ISO88591B2 Keycode = Key2 | altgrMask // 178 ² SUPERSCRIPT TWO + ISO88591B3 Keycode = Key3 | altgrMask // 179 ³ SUPERSCRIPT THREE + ISO88591B4 Keycode = KeyQuote | altgrMask // 180 ´ ACUTE ACCENT + ISO88591B5 Keycode = KeyM | altgrMask // 181 µ MICRO SIGN + ISO88591B6 Keycode = KeySemicolon | altgrMask // 182 ¶ PILCROW SIGN + ISO88591B7 Keycode = 0 // 183 · MIDDLE DOT + ISO88591B8 Keycode = 0 // 184 ¸ CEDILLA + ISO88591B9 Keycode = Key1 | altgrMask | shiftMask // 185 ¹ SUPERSCRIPT ONE + ISO88591BA Keycode = 0 // 186 º MASCULINE ORDINAL + ISO88591BB Keycode = KeyRightBrace | altgrMask // 187 » RIGHT DOUBLE ANGLE QUOTE + ISO88591BC Keycode = Key6 | altgrMask // 188 ¼ FRACTION ONE QUARTER + ISO88591BD Keycode = Key7 | altgrMask // 189 ½ FRACTION ONE HALF + ISO88591BE Keycode = Key8 | altgrMask // 190 ¾ FRACTION THREE QUARTERS + ISO88591BF Keycode = KeySlash | altgrMask // 191 ¿ INVERTED QUESTION MARK + ISO88591C0 Keycode = graveAccentBits | KeyA | shiftMask // 192 À A GRAVE + ISO88591C1 Keycode = KeyA | altgrMask | shiftMask // 193 Á A ACUTE + ISO88591C2 Keycode = circumflexBits | KeyA | shiftMask // 194 Â A CIRCUMFLEX + ISO88591C3 Keycode = tildeBits | KeyA | shiftMask // 195 Ã A TILDE + ISO88591C4 Keycode = KeyQ | altgrMask | shiftMask // 196 Ä A DIAERESIS + ISO88591C5 Keycode = KeyW | altgrMask | shiftMask // 197 Å A RING ABOVE + ISO88591C6 Keycode = KeyZ | altgrMask | shiftMask // 198 Æ AE + ISO88591C7 Keycode = KeyComma | altgrMask | shiftMask // 199 Ç C CEDILLA + ISO88591C8 Keycode = graveAccentBits | KeyE | shiftMask // 200 È E GRAVE + ISO88591C9 Keycode = KeyE | altgrMask | shiftMask // 201 É E ACUTE + ISO88591CA Keycode = circumflexBits | KeyE | shiftMask // 202 Ê E CIRCUMFLEX + ISO88591CB Keycode = diaeresisBits | KeyE | shiftMask // 203 Ë E DIAERESIS + ISO88591CC Keycode = graveAccentBits | KeyI | shiftMask // 204 Ì I GRAVE + ISO88591CD Keycode = KeyI | altgrMask | shiftMask // 205 Í I ACUTE + ISO88591CE Keycode = circumflexBits | KeyI | shiftMask // 206 Î I CIRCUMFLEX + ISO88591CF Keycode = diaeresisBits | KeyI | shiftMask // 207 Ï I DIAERESIS + ISO88591D0 Keycode = KeyD | altgrMask | shiftMask // 208 Ð ETH + ISO88591D1 Keycode = KeyN | altgrMask | shiftMask // 209 Ñ N TILDE + ISO88591D2 Keycode = graveAccentBits | KeyO | shiftMask // 210 Ò O GRAVE + ISO88591D3 Keycode = KeyO | altgrMask | shiftMask // 211 Ó O ACUTE + ISO88591D4 Keycode = circumflexBits | KeyO | shiftMask // 212 Ô O CIRCUMFLEX + ISO88591D5 Keycode = tildeBits | KeyO | shiftMask // 213 Õ O TILDE + ISO88591D6 Keycode = KeyP | altgrMask | shiftMask // 214 Ö O DIAERESIS + ISO88591D7 Keycode = KeyEqual | altgrMask // 215 × MULTIPLICATION + ISO88591D8 Keycode = KeyL | altgrMask | shiftMask // 216 Ø O STROKE + ISO88591D9 Keycode = graveAccentBits | KeyU | shiftMask // 217 Ù U GRAVE + ISO88591DA Keycode = KeyU | altgrMask | shiftMask // 218 Ú U ACUTE + ISO88591DB Keycode = circumflexBits | KeyU | shiftMask // 219 Û U CIRCUMFLEX + ISO88591DC Keycode = KeyY | altgrMask | shiftMask // 220 Ü U DIAERESIS + ISO88591DD Keycode = acuteAccentBits | KeyY | shiftMask // 221 Ý Y ACUTE + ISO88591DE Keycode = KeyT | altgrMask | shiftMask // 222 Þ THORN + ISO88591DF Keycode = KeyS | altgrMask // 223 ß SHARP S + ISO88591E0 Keycode = graveAccentBits | KeyA // 224 à a GRAVE + ISO88591E1 Keycode = KeyA | altgrMask // 225 á a ACUTE + ISO88591E2 Keycode = circumflexBits | KeyA // 226 â a CIRCUMFLEX + ISO88591E3 Keycode = tildeBits | KeyA // 227 ã a TILDE + ISO88591E4 Keycode = diaeresisBits | KeyA // 228 ä a DIAERESIS + ISO88591E5 Keycode = KeyW | altgrMask // 229 å a RING ABOVE + ISO88591E6 Keycode = KeyZ | altgrMask // 230 æ ae + ISO88591E7 Keycode = KeyComma | altgrMask // 231 ç c CEDILLA + ISO88591E8 Keycode = graveAccentBits | KeyE // 232 è e GRAVE + ISO88591E9 Keycode = acuteAccentBits | KeyE // 233 é e ACUTE + ISO88591EA Keycode = circumflexBits | KeyE // 234 ê e CIRCUMFLEX + ISO88591EB Keycode = diaeresisBits | KeyE // 235 ë e DIAERESIS + ISO88591EC Keycode = graveAccentBits | KeyI // 236 ì i GRAVE + ISO88591ED Keycode = KeyI | altgrMask // 237 í i ACUTE + ISO88591EE Keycode = circumflexBits | KeyI // 238 î i CIRCUMFLEX + ISO88591EF Keycode = diaeresisBits | KeyI // 239 ï i DIAERESIS + ISO88591F0 Keycode = KeyD | altgrMask // 240 ð ETH + ISO88591F1 Keycode = KeyN | altgrMask // 241 ñ n TILDE + ISO88591F2 Keycode = graveAccentBits | KeyO // 242 ò o GRAVE + ISO88591F3 Keycode = KeyO | altgrMask // 243 ó o ACUTE + ISO88591F4 Keycode = circumflexBits | KeyO // 244 ô o CIRCUMFLEX + ISO88591F5 Keycode = tildeBits | KeyO // 245 õ o TILDE + ISO88591F6 Keycode = KeyP | altgrMask // 246 ö o DIAERESIS + ISO88591F7 Keycode = KeyEqual | altgrMask | shiftMask // 247 ÷ DIVISION + ISO88591F8 Keycode = KeyL | altgrMask // 248 ø o STROKE + ISO88591F9 Keycode = graveAccentBits | KeyU // 249 ù u GRAVE + ISO88591FA Keycode = KeyU | altgrMask // 250 ú u ACUTE + ISO88591FB Keycode = circumflexBits | KeyU // 251 û u CIRCUMFLEX + ISO88591FC Keycode = KeyY | altgrMask // 252 ü u DIAERESIS + ISO88591FD Keycode = acuteAccentBits | KeyY // 253 ý y ACUTE + ISO88591FE Keycode = KeyT | altgrMask // 254 þ THORN + ISO88591FF Keycode = diaeresisBits | KeyY // 255 ÿ y DIAERESIS + UNICODE20AC Keycode = Key5 | altgrMask // 20AC € Euro Sign +) + +var ascii = [...]Keycode{ + ASCII00.mask(), ASCII01.mask(), ASCII02.mask(), ASCII03.mask(), + ASCII04.mask(), ASCII05.mask(), ASCII06.mask(), ASCII07.mask(), + ASCII08.mask(), ASCII09.mask(), ASCII0A.mask(), ASCII0B.mask(), + ASCII0C.mask(), ASCII0D.mask(), ASCII0E.mask(), ASCII0F.mask(), + ASCII10.mask(), ASCII11.mask(), ASCII12.mask(), ASCII13.mask(), + ASCII14.mask(), ASCII15.mask(), ASCII16.mask(), ASCII17.mask(), + ASCII18.mask(), ASCII19.mask(), ASCII1A.mask(), ASCII1B.mask(), + ASCII1C.mask(), ASCII1D.mask(), ASCII1E.mask(), ASCII1F.mask(), + ASCII20.mask(), ASCII21.mask(), ASCII22.mask(), ASCII23.mask(), + ASCII24.mask(), ASCII25.mask(), ASCII26.mask(), ASCII27.mask(), + ASCII28.mask(), ASCII29.mask(), ASCII2A.mask(), ASCII2B.mask(), + ASCII2C.mask(), ASCII2D.mask(), ASCII2E.mask(), ASCII2F.mask(), + ASCII30.mask(), ASCII31.mask(), ASCII32.mask(), ASCII33.mask(), + ASCII34.mask(), ASCII35.mask(), ASCII36.mask(), ASCII37.mask(), + ASCII38.mask(), ASCII39.mask(), ASCII3A.mask(), ASCII3B.mask(), + ASCII3C.mask(), ASCII3D.mask(), ASCII3E.mask(), ASCII3F.mask(), + ASCII40.mask(), ASCII41.mask(), ASCII42.mask(), ASCII43.mask(), + ASCII44.mask(), ASCII45.mask(), ASCII46.mask(), ASCII47.mask(), + ASCII48.mask(), ASCII49.mask(), ASCII4A.mask(), ASCII4B.mask(), + ASCII4C.mask(), ASCII4D.mask(), ASCII4E.mask(), ASCII4F.mask(), + ASCII50.mask(), ASCII51.mask(), ASCII52.mask(), ASCII53.mask(), + ASCII54.mask(), ASCII55.mask(), ASCII56.mask(), ASCII57.mask(), + ASCII58.mask(), ASCII59.mask(), ASCII5A.mask(), ASCII5B.mask(), + ASCII5C.mask(), ASCII5D.mask(), ASCII5E.mask(), ASCII5F.mask(), + ASCII60.mask(), ASCII61.mask(), ASCII62.mask(), ASCII63.mask(), + ASCII64.mask(), ASCII65.mask(), ASCII66.mask(), ASCII67.mask(), + ASCII68.mask(), ASCII69.mask(), ASCII6A.mask(), ASCII6B.mask(), + ASCII6C.mask(), ASCII6D.mask(), ASCII6E.mask(), ASCII6F.mask(), + ASCII70.mask(), ASCII71.mask(), ASCII72.mask(), ASCII73.mask(), + ASCII74.mask(), ASCII75.mask(), ASCII76.mask(), ASCII77.mask(), + ASCII78.mask(), ASCII79.mask(), ASCII7A.mask(), ASCII7B.mask(), + ASCII7C.mask(), ASCII7D.mask(), ASCII7E.mask(), ASCII7F.mask(), +} + +var iso88591 = [...]Keycode{ + ISO88591A0.mask(), ISO88591A1.mask(), ISO88591A2.mask(), ISO88591A3.mask(), + ISO88591A4.mask(), ISO88591A5.mask(), ISO88591A6.mask(), ISO88591A7.mask(), + ISO88591A8.mask(), ISO88591A9.mask(), ISO88591AA.mask(), ISO88591AB.mask(), + ISO88591AC.mask(), ISO88591AD.mask(), ISO88591AE.mask(), ISO88591AF.mask(), + ISO88591B0.mask(), ISO88591B1.mask(), ISO88591B2.mask(), ISO88591B3.mask(), + ISO88591B4.mask(), ISO88591B5.mask(), ISO88591B6.mask(), ISO88591B7.mask(), + ISO88591B8.mask(), ISO88591B9.mask(), ISO88591BA.mask(), ISO88591BB.mask(), + ISO88591BC.mask(), ISO88591BD.mask(), ISO88591BE.mask(), ISO88591BF.mask(), + ISO88591C0.mask(), ISO88591C1.mask(), ISO88591C2.mask(), ISO88591C3.mask(), + ISO88591C4.mask(), ISO88591C5.mask(), ISO88591C6.mask(), ISO88591C7.mask(), + ISO88591C8.mask(), ISO88591C9.mask(), ISO88591CA.mask(), ISO88591CB.mask(), + ISO88591CC.mask(), ISO88591CD.mask(), ISO88591CE.mask(), ISO88591CF.mask(), + ISO88591D0.mask(), ISO88591D1.mask(), ISO88591D2.mask(), ISO88591D3.mask(), + ISO88591D4.mask(), ISO88591D5.mask(), ISO88591D6.mask(), ISO88591D7.mask(), + ISO88591D8.mask(), ISO88591D9.mask(), ISO88591DA.mask(), ISO88591DB.mask(), + ISO88591DC.mask(), ISO88591DD.mask(), ISO88591DE.mask(), ISO88591DF.mask(), + ISO88591E0.mask(), ISO88591E1.mask(), ISO88591E2.mask(), ISO88591E3.mask(), + ISO88591E4.mask(), ISO88591E5.mask(), ISO88591E6.mask(), ISO88591E7.mask(), + ISO88591E8.mask(), ISO88591E9.mask(), ISO88591EA.mask(), ISO88591EB.mask(), + ISO88591EC.mask(), ISO88591ED.mask(), ISO88591EE.mask(), ISO88591EF.mask(), + ISO88591F0.mask(), ISO88591F1.mask(), ISO88591F2.mask(), ISO88591F3.mask(), + ISO88591F4.mask(), ISO88591F5.mask(), ISO88591F6.mask(), ISO88591F7.mask(), + ISO88591F8.mask(), ISO88591F9.mask(), ISO88591FA.mask(), ISO88591FB.mask(), + ISO88591FC.mask(), ISO88591FD.mask(), ISO88591FE.mask(), ISO88591FF.mask(), +} diff --git a/src/machine/usb/hid/mouse/mouse.go b/src/machine/usb/hid/mouse/mouse.go new file mode 100644 index 000000000..c412f51e0 --- /dev/null +++ b/src/machine/usb/hid/mouse/mouse.go @@ -0,0 +1,90 @@ +package mouse + +import ( + "machine/usb/hid" +) + +var Mouse *mouse + +type mouse struct { + buf *hid.RingBuffer +} + +func init() { + if Mouse == nil { + Mouse = newMouse() + hid.SetCallbackHandler(Mouse) + } +} + +// New returns hid-mouse. +func New() *mouse { + return Mouse +} + +func newMouse() *mouse { + return &mouse{ + buf: hid.NewRingBuffer(), + } +} + +func (m *mouse) Callback() bool { + if b, ok := m.buf.Get(); ok { + hid.SendUSBPacket(b[:5]) + return true + } + return false +} + +// Move is a function that moves the mouse cursor. +func (m *mouse) Move(vx, vy int) { + if vx == 0 && vy == 0 { + return + } + + if vx < -128 { + vx = -128 + } + if vx > 127 { + vx = 127 + } + + if vy < -128 { + vy = -128 + } + if vy > 127 { + vy = 127 + } + + m.buf.Put([]byte{ + 0x01, 0x00, byte(vx), byte(vy), 0x00, + }) +} + +// WHEEL controls the mouse wheel. +func (m *mouse) Wheel(v int) { + if v == 0 { + return + } + + if v < -128 { + v = -128 + } + if v > 127 { + v = 127 + } + + m.buf.Put([]byte{ + 0x01, 0x00, 0x00, 0x00, byte(v), + }) +} + +// WheelDown turns the mouse wheel down. +func (m *mouse) WheelDown() { + m.Wheel(-1) +} + +// WheelUp turns the mouse wheel up. +func (m *mouse) WheelUp() { + m.Wheel(1) +} diff --git a/src/machine/usb_descriptor.go b/src/machine/usb_descriptor.go new file mode 100644 index 000000000..9a1220c42 --- /dev/null +++ b/src/machine/usb_descriptor.go @@ -0,0 +1,70 @@ +//go:build sam || nrf52840 +// +build sam nrf52840 + +package machine + +type USBDescriptor struct { + Device []byte + Configuration []byte + HID map[uint16][]byte +} + +func (d *USBDescriptor) Configure(idVendor, idProduct uint16) { + d.Device[8] = byte(idVendor) + d.Device[9] = byte(idVendor >> 8) + d.Device[10] = byte(idProduct) + d.Device[11] = byte(idProduct >> 8) +} + +var descriptorCDC = USBDescriptor{ + Device: []byte{ + 0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01, + }, + Configuration: []byte{ + 0x09, 0x02, 0x4b, 0x00, 0x02, 0x01, 0x00, 0xa0, 0x32, + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, + 0x05, 0x24, 0x00, 0x10, 0x01, + 0x04, 0x24, 0x02, 0x06, + 0x05, 0x24, 0x06, 0x00, 0x01, + 0x05, 0x24, 0x01, 0x01, 0x01, + 0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10, + 0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00, + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, + }, +} + +var descriptorCDCHID = USBDescriptor{ + Device: []byte{ + 0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01, + }, + Configuration: []byte{ + 0x09, 0x02, 0x64, 0x00, 0x03, 0x01, 0x00, 0xa0, 0x32, + 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, + 0x05, 0x24, 0x00, 0x10, 0x01, + 0x04, 0x24, 0x02, 0x06, + 0x05, 0x24, 0x06, 0x00, 0x01, + 0x05, 0x24, 0x01, 0x01, 0x01, + 0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10, + 0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00, + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, + 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x09, 0x21, 0x01, 0x01, 0x00, 0x01, 0x22, 0x65, 0x00, + 0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x01, + }, + HID: map[uint16][]byte{ + 2: []byte{ + // keyboard and mouse + 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x85, 0x02, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, + 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x03, 0x95, 0x06, + 0x75, 0x08, 0x15, 0x00, 0x25, 0x73, 0x05, 0x07, 0x19, 0x00, 0x29, 0x73, 0x81, 0x00, 0xc0, 0x05, + 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x85, 0x01, 0x05, 0x09, 0x19, 0x01, 0x29, + 0x03, 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, + 0x03, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 0x95, + 0x03, 0x81, 0x06, 0xc0, 0xc0, + }, + }, +} |