Skip to content

Commit 1b2e764

Browse files
sago35deadprogram
authored andcommitted
samd21,samd51,nrf52840: add support for USBHID (keyboard / mouse)
1 parent 2c93a40 commit 1b2e764

File tree

13 files changed

+1510
-479
lines changed

13 files changed

+1510
-479
lines changed

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,10 @@ smoketest:
414414
@$(MD5SUM) test.hex
415415
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
416416
@$(MD5SUM) test.hex
417+
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse
418+
@$(MD5SUM) test.hex
419+
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
420+
@$(MD5SUM) test.hex
417421
# test simulated boards on play.tinygo.org
418422
ifneq ($(WASM), 0)
419423
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
@@ -555,6 +559,11 @@ endif
555559
@$(MD5SUM) test.hex
556560
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
557561
@$(MD5SUM) test.hex
562+
# test usbhid
563+
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/hid-keyboard
564+
@$(MD5SUM) test.hex
565+
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/hid-keyboard
566+
@$(MD5SUM) test.hex
558567
ifneq ($(STM32), 0)
559568
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
560569
@$(MD5SUM) test.hex

src/examples/hid-keyboard/main.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package main
2+
3+
import (
4+
"machine"
5+
"machine/usb/hid/keyboard"
6+
"time"
7+
)
8+
9+
func main() {
10+
button := machine.BUTTON
11+
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
12+
13+
kb := keyboard.New()
14+
15+
for {
16+
if !button.Get() {
17+
kb.Write([]byte("tinygo"))
18+
time.Sleep(200 * time.Millisecond)
19+
}
20+
}
21+
}

src/examples/hid-mouse/main.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package main
2+
3+
import (
4+
"machine"
5+
"machine/usb/hid/mouse"
6+
"time"
7+
)
8+
9+
func main() {
10+
button := machine.BUTTON
11+
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
12+
13+
mouse := mouse.New()
14+
15+
for {
16+
if !button.Get() {
17+
for j := 0; j < 5; j++ {
18+
for i := 0; i < 100; i++ {
19+
mouse.Move(1, 0)
20+
time.Sleep(1 * time.Millisecond)
21+
}
22+
23+
for i := 0; i < 100; i++ {
24+
mouse.Move(0, 1)
25+
time.Sleep(1 * time.Millisecond)
26+
}
27+
28+
for i := 0; i < 100; i++ {
29+
mouse.Move(-1, -1)
30+
time.Sleep(1 * time.Millisecond)
31+
}
32+
}
33+
34+
time.Sleep(100 * time.Millisecond)
35+
}
36+
}
37+
}

src/machine/machine_atsamd21.go

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,7 +1746,8 @@ type USBCDC struct {
17461746
}
17471747

17481748
var (
1749-
USB = &USBCDC{Buffer: NewRingBuffer()}
1749+
USB = &USBCDC{Buffer: NewRingBuffer()}
1750+
waitHidTxc bool
17501751
)
17511752

17521753
const (
@@ -1999,6 +2000,9 @@ func handleUSB(intr interrupt.Interrupt) {
19992000
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
20002001
USB.Flush()
20012002
// if you want to blink LED showing traffic, this would be the place...
2003+
if hidCallback != nil && !waitHidTxc {
2004+
hidCallback()
2005+
}
20022006
}
20032007

20042008
// Endpoint 0 Setup interrupt
@@ -2021,6 +2025,9 @@ func handleUSB(intr interrupt.Interrupt) {
20212025
// Class Interface Requests
20222026
if setup.wIndex == usb_CDC_ACM_INTERFACE {
20232027
ok = cdcSetup(setup)
2028+
} else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
2029+
sendZlp()
2030+
ok = true
20242031
}
20252032
}
20262033

@@ -2059,6 +2066,9 @@ func handleUSB(intr interrupt.Interrupt) {
20592066
if i == usb_CDC_ENDPOINT_IN {
20602067
USB.waitTxc = false
20612068
}
2069+
case usb_HID_ENDPOINT_IN:
2070+
setEPINTFLAG(i, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
2071+
waitHidTxc = false
20622072
}
20632073
}
20642074
}
@@ -2156,7 +2166,7 @@ func handleStandardSetup(setup usbSetup) bool {
21562166
}
21572167
}
21582168

2159-
sendUSBPacket(0, buf)
2169+
sendUSBPacket(0, buf, setup.wLength)
21602170
return true
21612171

21622172
case usb_CLEAR_FEATURE:
@@ -2212,7 +2222,7 @@ func handleStandardSetup(setup usbSetup) bool {
22122222

22132223
case usb_GET_CONFIGURATION:
22142224
buff := []byte{usbConfiguration}
2215-
sendUSBPacket(0, buff)
2225+
sendUSBPacket(0, buff, setup.wLength)
22162226
return true
22172227

22182228
case usb_SET_CONFIGURATION:
@@ -2229,6 +2239,11 @@ func handleStandardSetup(setup usbSetup) bool {
22292239
// Enable interrupt for CDC data messages from host
22302240
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_EPINTENSET_TRCPT0)
22312241

2242+
// Enable interrupt for HID messages from host
2243+
if hidCallback != nil {
2244+
setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_EPINTENSET_TRCPT1)
2245+
}
2246+
22322247
sendZlp()
22332248
return true
22342249
} else {
@@ -2237,7 +2252,7 @@ func handleStandardSetup(setup usbSetup) bool {
22372252

22382253
case usb_GET_INTERFACE:
22392254
buff := []byte{usbSetInterface}
2240-
sendUSBPacket(0, buff)
2255+
sendUSBPacket(0, buff, setup.wLength)
22412256
return true
22422257

22432258
case usb_SET_INTERFACE:
@@ -2263,7 +2278,7 @@ func cdcSetup(setup usbSetup) bool {
22632278
b[5] = byte(usbLineInfo.bParityType)
22642279
b[6] = byte(usbLineInfo.bDataBits)
22652280

2266-
sendUSBPacket(0, b[:])
2281+
sendUSBPacket(0, b[:], setup.wLength)
22672282
return true
22682283
}
22692284
}
@@ -2306,9 +2321,31 @@ func cdcSetup(setup usbSetup) bool {
23062321
return false
23072322
}
23082323

2324+
// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
2325+
func SendUSBHIDPacket(ep uint32, data []byte) bool {
2326+
if waitHidTxc {
2327+
return false
2328+
}
2329+
sendUSBPacket(ep, data, 0)
2330+
2331+
// clear transfer complete flag
2332+
setEPINTFLAG(ep, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
2333+
2334+
// send data by setting bank ready
2335+
setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
2336+
2337+
waitHidTxc = true
2338+
2339+
return true
2340+
}
2341+
23092342
//go:noinline
2310-
func sendUSBPacket(ep uint32, data []byte) {
2311-
copy(udd_ep_in_cache_buffer[ep][:], data)
2343+
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
2344+
l := uint16(len(data))
2345+
if 0 < maxsize && maxsize < l {
2346+
l = maxsize
2347+
}
2348+
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
23122349

23132350
// Set endpoint address for sending data
23142351
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) {
23182355

23192356
// set byte count, which is total number of bytes to be sent
23202357
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
2321-
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos))
2358+
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
23222359
}
23232360

23242361
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {

src/machine/machine_atsamd51.go

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,7 +1987,8 @@ type USBCDC struct {
19871987

19881988
var (
19891989
// USB is a USB CDC interface.
1990-
USB = &USBCDC{Buffer: NewRingBuffer()}
1990+
USB = &USBCDC{Buffer: NewRingBuffer()}
1991+
waitHidTxc bool
19911992
)
19921993

19931994
const (
@@ -2241,6 +2242,9 @@ func handleUSBIRQ(interrupt.Interrupt) {
22412242
// Start of frame
22422243
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
22432244
USB.Flush()
2245+
if hidCallback != nil && !waitHidTxc {
2246+
hidCallback()
2247+
}
22442248
// if you want to blink LED showing traffic, this would be the place...
22452249
}
22462250

@@ -2264,6 +2268,9 @@ func handleUSBIRQ(interrupt.Interrupt) {
22642268
// Class Interface Requests
22652269
if setup.wIndex == usb_CDC_ACM_INTERFACE {
22662270
ok = cdcSetup(setup)
2271+
} else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
2272+
sendZlp()
2273+
ok = true
22672274
}
22682275
}
22692276

@@ -2302,6 +2309,9 @@ func handleUSBIRQ(interrupt.Interrupt) {
23022309
if i == usb_CDC_ENDPOINT_IN {
23032310
USB.waitTxc = false
23042311
}
2312+
case usb_HID_ENDPOINT_IN:
2313+
setEPINTFLAG(i, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
2314+
waitHidTxc = false
23052315
}
23062316
}
23072317
}
@@ -2399,7 +2409,7 @@ func handleStandardSetup(setup usbSetup) bool {
23992409
}
24002410
}
24012411

2402-
sendUSBPacket(0, buf)
2412+
sendUSBPacket(0, buf, setup.wLength)
24032413
return true
24042414

24052415
case usb_CLEAR_FEATURE:
@@ -2455,7 +2465,7 @@ func handleStandardSetup(setup usbSetup) bool {
24552465

24562466
case usb_GET_CONFIGURATION:
24572467
buff := []byte{usbConfiguration}
2458-
sendUSBPacket(0, buff)
2468+
sendUSBPacket(0, buff, setup.wLength)
24592469
return true
24602470

24612471
case usb_SET_CONFIGURATION:
@@ -2472,6 +2482,11 @@ func handleStandardSetup(setup usbSetup) bool {
24722482
// Enable interrupt for CDC data messages from host
24732483
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
24742484

2485+
// Enable interrupt for HID messages from host
2486+
if hidCallback != nil {
2487+
setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
2488+
}
2489+
24752490
sendZlp()
24762491
return true
24772492
} else {
@@ -2480,7 +2495,7 @@ func handleStandardSetup(setup usbSetup) bool {
24802495

24812496
case usb_GET_INTERFACE:
24822497
buff := []byte{usbSetInterface}
2483-
sendUSBPacket(0, buff)
2498+
sendUSBPacket(0, buff, setup.wLength)
24842499
return true
24852500

24862501
case usb_SET_INTERFACE:
@@ -2506,7 +2521,7 @@ func cdcSetup(setup usbSetup) bool {
25062521
b[5] = byte(usbLineInfo.bParityType)
25072522
b[6] = byte(usbLineInfo.bDataBits)
25082523

2509-
sendUSBPacket(0, b[:])
2524+
sendUSBPacket(0, b[:], setup.wLength)
25102525
return true
25112526
}
25122527
}
@@ -2549,9 +2564,32 @@ func cdcSetup(setup usbSetup) bool {
25492564
return false
25502565
}
25512566

2567+
// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
2568+
func SendUSBHIDPacket(ep uint32, data []byte) bool {
2569+
if waitHidTxc {
2570+
return false
2571+
}
2572+
2573+
sendUSBPacket(ep, data, 0)
2574+
2575+
// clear transfer complete flag
2576+
setEPINTFLAG(ep, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
2577+
2578+
// send data by setting bank ready
2579+
setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
2580+
2581+
waitHidTxc = true
2582+
2583+
return true
2584+
}
2585+
25522586
//go:noinline
2553-
func sendUSBPacket(ep uint32, data []byte) {
2554-
copy(udd_ep_in_cache_buffer[ep][:], data)
2587+
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
2588+
l := uint16(len(data))
2589+
if 0 < maxsize && maxsize < l {
2590+
l = maxsize
2591+
}
2592+
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
25552593

25562594
// Set endpoint address for sending data
25572595
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) {
25612599

25622600
// set byte count, which is total number of bytes to be sent
25632601
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
2564-
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos))
2602+
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
25652603
}
25662604

25672605
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {

0 commit comments

Comments
 (0)