Browse Source

Add USB mouse & joystick for Teensy 4.0

teensy4-core
PaulStoffregen 5 years ago
parent
commit
1f1e5c29e1
8 changed files with 684 additions and 49 deletions
  1. +2
    -2
      teensy4/WProgram.h
  2. +8
    -0
      teensy4/usb.c
  3. +23
    -46
      teensy4/usb_desc.h
  4. +109
    -0
      teensy4/usb_joystick.c
  5. +194
    -0
      teensy4/usb_joystick.h
  6. +1
    -1
      teensy4/usb_keyboard.c
  7. +236
    -0
      teensy4/usb_mouse.c
  8. +111
    -0
      teensy4/usb_mouse.h

+ 2
- 2
teensy4/WProgram.h View File

@@ -51,8 +51,8 @@
#include "usb_serial.h"
#include "usb_seremu.h"
#include "usb_keyboard.h"
//#include "usb_mouse.h"
//#include "usb_joystick.h"
#include "usb_mouse.h"
#include "usb_joystick.h"
//#include "usb_midi.h"
#include "usb_rawhid.h"
//#include "usb_flightsim.h"

+ 8
- 0
teensy4/usb.c View File

@@ -4,6 +4,8 @@
#include "usb_serial.h"
#include "usb_seremu.h"
#include "usb_keyboard.h"
#include "usb_mouse.h"
#include "usb_joystick.h"
#include "core_pins.h" // for delay()
#include "avr/pgmspace.h"
#include <string.h>
@@ -370,6 +372,12 @@ static void endpoint0_setup(uint64_t setupdata)
#if defined(KEYBOARD_INTERFACE)
usb_keyboard_configure();
#endif
#if defined(MOUSE_INTERFACE)
usb_mouse_configure();
#endif
#if defined(JOYSTICK_INTERFACE)
usb_joystick_configure();
#endif
endpoint0_receive(NULL, 0, 0);
return;
case 0x0880: // GET_CONFIGURATION

+ 23
- 46
teensy4/usb_desc.h View File

@@ -78,12 +78,6 @@ interfaces, usually these other settings should not be changed.

Edit NUM_ENDPOINTS to be at least the largest endpoint number used.

Edit NUM_USB_BUFFERS to control how much memory the USB stack will
allocate. At least 2 should be used for each endpoint. More
memory will allow higher throughput for user programs that have
high latency (eg, spending time doing things other than interacting
with the USB).

Edit the ENDPOINT*_CONFIG lines so each endpoint is configured
the proper way (transmit, receive, or both).

@@ -185,7 +179,7 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define NUM_USB_BUFFERS 24
#define NUM_INTERFACE 5
#define SEREMU_INTERFACE 2 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_ENDPOINT 2
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
@@ -196,7 +190,7 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define KEYMEDIA_INTERFACE 4 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 6
#define KEYMEDIA_ENDPOINT 4
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define MOUSE_INTERFACE 1 // Mouse
@@ -204,15 +198,14 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define MOUSE_SIZE 8
#define MOUSE_INTERVAL 1
#define JOYSTICK_INTERFACE 3 // Joystick
#define JOYSTICK_ENDPOINT 4
#define JOYSTICK_ENDPOINT 6
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick
#define JOYSTICK_INTERVAL 2
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_INTERRUPT + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT6_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT

#elif defined(USB_SERIAL_HID)
#define VENDOR_ID 0x16C0
@@ -226,40 +219,40 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 30
#define EP0_SIZE 64
#define NUM_ENDPOINTS 7
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 6
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
#define CDC_ACM_ENDPOINT 2
#define CDC_RX_ENDPOINT 3
#define CDC_TX_ENDPOINT 4
#define CDC_TX_ENDPOINT 3
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define CDC_RX_SIZE_480 512
#define CDC_TX_SIZE_480 512
#define CDC_RX_SIZE_12 64
#define CDC_TX_SIZE_12 64
#define KEYBOARD_INTERFACE 2 // Keyboard
#define KEYBOARD_ENDPOINT 1
#define KEYBOARD_ENDPOINT 4
#define KEYBOARD_SIZE 8
#define KEYBOARD_INTERVAL 1
#define KEYMEDIA_INTERFACE 5 // Keyboard Media Keys
#define KEYMEDIA_ENDPOINT 7
#define KEYMEDIA_ENDPOINT 5
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
#define MOUSE_INTERFACE 3 // Mouse
#define MOUSE_ENDPOINT 5
#define MOUSE_ENDPOINT 6
#define MOUSE_SIZE 8
#define MOUSE_INTERVAL 2
#define JOYSTICK_INTERFACE 4 // Joystick
#define JOYSTICK_ENDPOINT 6
#define JOYSTICK_ENDPOINT 7
#define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick
#define JOYSTICK_INTERVAL 1
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_BULK + ENDPOINT_TRANSMIT_BULK
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT6_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT

#elif defined(USB_TOUCHSCREEN)
#define VENDOR_ID 0x16C0
@@ -270,7 +263,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 20
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 15
#define NUM_INTERFACE 4
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
@@ -306,7 +298,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 26
#define EP0_SIZE 64
#define NUM_ENDPOINTS 6
#define NUM_USB_BUFFERS 20
#define NUM_INTERFACE 5
#define SEREMU_INTERFACE 2 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
@@ -347,7 +338,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 11
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 2
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
@@ -377,7 +367,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 13
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 2
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
@@ -407,7 +396,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 14
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 2
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
@@ -436,7 +424,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 11
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 3
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
@@ -469,7 +456,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 13
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 3
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
@@ -502,7 +488,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 14
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 3
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
@@ -536,7 +521,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 18
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 12
#define NUM_INTERFACE 2
#define RAWHID_INTERFACE 0 // RawHID
#define RAWHID_TX_ENDPOINT 3
@@ -565,7 +549,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 26
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 20
#define NUM_INTERFACE 2
#define FLIGHTSIM_INTERFACE 0 // Flight Sim Control
#define FLIGHTSIM_TX_ENDPOINT 3
@@ -596,7 +579,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 26
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 20
#define NUM_INTERFACE 3
#define FLIGHTSIM_INTERFACE 0 // Flight Sim Control
#define FLIGHTSIM_TX_ENDPOINT 3
@@ -632,7 +614,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 15
#define EP0_SIZE 64
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 20
#define NUM_INTERFACE 2
#define MTP_INTERFACE 0 // MTP Disk
#define MTP_TX_ENDPOINT 3
@@ -663,7 +644,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 12
#define EP0_SIZE 64
#define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 4
#define SEREMU_INTERFACE 0 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
@@ -693,7 +673,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 17
#define EP0_SIZE 64
#define NUM_ENDPOINTS 8
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 6
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
@@ -735,7 +714,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 20
#define EP0_SIZE 64
#define NUM_ENDPOINTS 8
#define NUM_USB_BUFFERS 30
#define NUM_INTERFACE 6
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
@@ -781,7 +759,6 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define PRODUCT_NAME_LEN 14
#define EP0_SIZE 64
#define NUM_ENDPOINTS 15
#define NUM_USB_BUFFERS 31
#define NUM_INTERFACE 13
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0

+ 109
- 0
teensy4/usb_joystick.c View File

@@ -0,0 +1,109 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2017 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#include "usb_dev.h"
#include "usb_joystick.h"
#include "core_pins.h" // for yield()
#include <string.h> // for memcpy()
#include "avr/pgmspace.h" // for PROGMEM, DMAMEM, FASTRUN
#include "debug/printf.h"
#include "core_pins.h"


#ifdef JOYSTICK_INTERFACE // defined by usb_dev.h -> usb_desc.h


uint32_t usb_joystick_data[(JOYSTICK_SIZE+3)/4];

static uint8_t transmit_previous_timeout=0;

// When the PC isn't listening, how long do we wait before discarding data?
#define TX_TIMEOUT_MSEC 30

#define TX_NUM 4
#if JOYSTICK_SIZE <= 32
#define TX_BUFSIZE 32
#else
#define TX_BUFSIZE 64
#endif
static transfer_t tx_transfer[TX_NUM] __attribute__ ((used, aligned(32)));
DMAMEM static uint8_t txbuffer[TX_NUM * TX_BUFSIZE] __attribute__ ((aligned(32)));
static uint8_t tx_head=0;
#if JOYSTICK_SIZE > TX_BUFSIZE
#error "Internal error, transmit buffer size is too small for joystick endpoint"
#endif


void usb_joystick_configure(void)
{
memset(tx_transfer, 0, sizeof(tx_transfer));
tx_head = 0;
usb_config_tx(JOYSTICK_ENDPOINT, JOYSTICK_SIZE, 0, NULL);
}


int usb_joystick_send()
{
if (!usb_configuration) return -1;
uint32_t head = tx_head;
transfer_t *xfer = tx_transfer + head;
uint32_t wait_begin_at = systick_millis_count;
while (1) {
uint32_t status = usb_transfer_status(xfer);
if (!(status & 0x80)) {
if (status & 0x68) {
// TODO: what if status has errors???
printf("ERROR status = %x, i=%d, ms=%u\n",
status, tx_head, systick_millis_count);
}
transmit_previous_timeout = 0;
break;
}
if (transmit_previous_timeout) return -1;
if (systick_millis_count - wait_begin_at > TX_TIMEOUT_MSEC) {
// waited too long, assume the USB host isn't listening
transmit_previous_timeout = 1;
return -1;
}
if (!usb_configuration) return -1;
yield();
}
uint8_t *buffer = txbuffer + head * TX_BUFSIZE;
memcpy(buffer, usb_joystick_data, JOYSTICK_SIZE);
usb_prepare_transfer(xfer, buffer, JOYSTICK_SIZE, 0);
arm_dcache_flush_delete(buffer, TX_BUFSIZE);
usb_transmit(JOYSTICK_ENDPOINT, xfer);
if (++head >= TX_NUM) head = 0;
tx_head = head;
return 0;
}


#endif // JOYSTICK_INTERFACE

+ 194
- 0
teensy4/usb_joystick.h View File

@@ -0,0 +1,194 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2017 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef USBjoystick_h_
#define USBjoystick_h_

#include "usb_desc.h"

#if defined(JOYSTICK_INTERFACE)

#include <inttypes.h>

// C language implementation
#ifdef __cplusplus
extern "C" {
#endif
void usb_joystick_configure(void);
int usb_joystick_send(void);
extern uint32_t usb_joystick_data[(JOYSTICK_SIZE+3)/4];
extern volatile uint8_t usb_configuration;
#ifdef __cplusplus
}
#endif

// C++ interface
#ifdef __cplusplus
class usb_joystick_class
{
public:
void begin(void) { }
void end(void) { }
#if JOYSTICK_SIZE == 12
void button(uint8_t button, bool val) {
if (--button >= 32) return;
if (val) usb_joystick_data[0] |= (1 << button);
else usb_joystick_data[0] &= ~(1 << button);
if (!manual_mode) usb_joystick_send();
}
void X(unsigned int val) {
if (val > 1023) val = 1023;
usb_joystick_data[1] = (usb_joystick_data[1] & 0xFFFFC00F) | (val << 4);
if (!manual_mode) usb_joystick_send();
}
void Y(unsigned int val) {
if (val > 1023) val = 1023;
usb_joystick_data[1] = (usb_joystick_data[1] & 0xFF003FFF) | (val << 14);
if (!manual_mode) usb_joystick_send();
}
void position(unsigned int x, unsigned int y) {
if (x > 1023) x = 1023;
if (y > 1023) y = 1023;
usb_joystick_data[1] = (usb_joystick_data[1] & 0xFFF00000)
| (x << 4) | (y << 14);
if (!manual_mode) usb_joystick_send();
}
void Z(unsigned int val) {
if (val > 1023) val = 1023;
usb_joystick_data[1] = (usb_joystick_data[1] & 0x00FFFFFF) | (val << 24);
usb_joystick_data[2] = (usb_joystick_data[2] & 0xFFFFFFFC) | (val >> 8);
if (!manual_mode) usb_joystick_send();
}
void Zrotate(unsigned int val) {
if (val > 1023) val = 1023;
usb_joystick_data[2] = (usb_joystick_data[2] & 0xFFFFF003) | (val << 2);
if (!manual_mode) usb_joystick_send();
}
void sliderLeft(unsigned int val) {
if (val > 1023) val = 1023;
usb_joystick_data[2] = (usb_joystick_data[2] & 0xFFC00FFF) | (val << 12);
if (!manual_mode) usb_joystick_send();
}
void sliderRight(unsigned int val) {
if (val > 1023) val = 1023;
usb_joystick_data[2] = (usb_joystick_data[2] & 0x003FFFFF) | (val << 22);
if (!manual_mode) usb_joystick_send();
}
void slider(unsigned int val) {
if (val > 1023) val = 1023;
usb_joystick_data[2] = (usb_joystick_data[2] & 0x00000FFF)
| (val << 12) | (val << 22);
if (!manual_mode) usb_joystick_send();
}
inline void hat(int dir) {
uint32_t val = 0;
if (dir < 0) val = 15;
else if (dir < 23) val = 0;
else if (dir < 68) val = 1;
else if (dir < 113) val = 2;
else if (dir < 158) val = 3;
else if (dir < 203) val = 4;
else if (dir < 245) val = 5;
else if (dir < 293) val = 6;
else if (dir < 338) val = 7;
usb_joystick_data[1] = (usb_joystick_data[1] & 0xFFFFFFF0) | val;
if (!manual_mode) usb_joystick_send();
}
#elif JOYSTICK_SIZE == 64
void button(unsigned int num, bool val) {
if (--num >= 128) return;
uint32_t *p = usb_joystick_data + (num >> 5);
num &= 0x1F;
if (val) *p |= (1 << num);
else *p &= ~(1 << num);
if (!manual_mode) usb_joystick_send();
}
void X(unsigned int position) { analog16(0, position); }
void Y(unsigned int position) { analog16(1, position); }
void Z(unsigned int position) { analog16(2, position); }
void Xrotate(unsigned int position) { analog16(3, position); }
void Yrotate(unsigned int position) { analog16(4, position); }
void Zrotate(unsigned int position) { analog16(5, position); }
void slider(unsigned int num, unsigned int position) {
if (--num >= 17) return;
analog16(num + 6, position);
}
inline void hat(unsigned int num, int angle) {
uint32_t val=15;
if (angle > 0 && angle < 23) val = 0;
else if (angle < 68) val = 1;
else if (angle < 113) val = 2;
else if (angle < 158) val = 3;
else if (angle < 203) val = 4;
else if (angle < 245) val = 5;
else if (angle < 293) val = 6;
else if (angle < 338) val = 7;
else if (angle < 360) val = 0;
uint32_t *p = usb_joystick_data;
switch(num) {
case 1:
p[15] = (p[15] & 0xFFF0FFFF) | (val << 16); break;
case 2:
p[15] = (p[15] & 0xFF0FFFFF) | (val << 20); break;
case 3:
p[15] = (p[15] & 0xF0FFFFFF) | (val << 24); break;
case 4:
p[15] = (p[15] & 0x0FFFFFFF) | (val << 28); break;
default:
return;
}
if (!manual_mode) usb_joystick_send();
}
#endif
void useManualSend(bool mode) {
manual_mode = mode;
}
void send_now(void) {
usb_joystick_send();
}
private:
static uint8_t manual_mode;
#if JOYSTICK_SIZE == 64
void analog16(unsigned int num, unsigned int value) {
if (value > 0xFFFF) value = 0xFFFF;
uint16_t *p = (uint16_t *)(&usb_joystick_data[4]);
p[num] = value;
if (!manual_mode) usb_joystick_send();
}
#endif
};
extern usb_joystick_class Joystick;

#endif // __cplusplus

#endif // JOYSTICK_INTERFACE

#endif // USBjoystick_h_


+ 1
- 1
teensy4/usb_keyboard.c View File

@@ -518,7 +518,7 @@ static uint8_t transmit_previous_timeout=0;
// When the PC isn't listening, how long do we wait before discarding data?
#define TX_TIMEOUT_MSEC 50

int usb_keyboard_transmit(int endpoint, const uint8_t *data, uint32_t len)
static int usb_keyboard_transmit(int endpoint, const uint8_t *data, uint32_t len)
{
if (!usb_configuration) return -1;
uint32_t head = tx_head;

+ 236
- 0
teensy4/usb_mouse.c View File

@@ -0,0 +1,236 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2019 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#include "usb_dev.h"
#include "usb_mouse.h"
#include "core_pins.h" // for yield()
#include <string.h> // for memcpy()
#include "avr/pgmspace.h" // for PROGMEM, DMAMEM, FASTRUN
#include "debug/printf.h"
#include "core_pins.h"

#ifdef MOUSE_INTERFACE // defined by usb_dev.h -> usb_desc.h

// which buttons are currently pressed
uint8_t usb_mouse_buttons_state=0;

//#define DEFAULT_XRES 640
//#define DEFAULT_YRES 480

//#define DEFAULT_XRES 800
//#define DEFAULT_YRES 600

//#define DEFAULT_XRES 1024
//#define DEFAULT_YRES 768

//#define DEFAULT_XRES 1280
//#define DEFAULT_YRES 720

//#define DEFAULT_XRES 1280
//#define DEFAULT_YRES 800

#define DEFAULT_XRES 1366
#define DEFAULT_YRES 768

//#define DEFAULT_XRES 1440
//#define DEFAULT_YRES 900

//#define DEFAULT_XRES 1920
//#define DEFAULT_YRES 1080

//#define DEFAULT_XRES 2560
//#define DEFAULT_YRES 1440

//#define DEFAULT_XRES 2560
//#define DEFAULT_YRES 1600

//#define DEFAULT_XRES 2880
//#define DEFAULT_YRES 1800

//#define DEFAULT_XRES 3840
//#define DEFAULT_YRES 2160

//#define DEFAULT_XRES 7680
//#define DEFAULT_YRES 4320


#define DEFAULT_XSCALE ((0x80000000ul+DEFAULT_XRES/2)/DEFAULT_XRES)
#define DEFAULT_YSCALE ((0x80000000ul+DEFAULT_YRES/2)/DEFAULT_YRES)

static uint16_t usb_mouse_resolution_x=DEFAULT_XRES;
static uint16_t usb_mouse_resolution_y=DEFAULT_YRES;
static uint16_t usb_mouse_position_x=DEFAULT_XRES/2;
static uint16_t usb_mouse_position_y=DEFAULT_YRES/2;
static uint32_t usb_mouse_scale_x=DEFAULT_XSCALE;
static uint32_t usb_mouse_scale_y=DEFAULT_YSCALE;
static uint32_t usb_mouse_offset_x=DEFAULT_XSCALE/2-1;
static uint32_t usb_mouse_offset_y=DEFAULT_YSCALE/2-1;


#define TX_NUM 4
#define TX_BUFSIZE 32
static transfer_t tx_transfer[TX_NUM] __attribute__ ((used, aligned(32)));
DMAMEM static uint8_t txbuffer[TX_NUM * TX_BUFSIZE] __attribute__ ((aligned(32)));
static uint8_t tx_head=0;
#if MOUSE_SIZE > TX_BUFSIZE
#error "Internal error, transmit buffer size is too small for mouse endpoint"
#endif


void usb_mouse_configure(void)
{
memset(tx_transfer, 0, sizeof(tx_transfer));
tx_head = 0;
usb_config_tx(MOUSE_ENDPOINT, MOUSE_SIZE, 0, NULL);
}


// Set the mouse buttons. To create a "click", 2 calls are needed,
// one to push the button down and the second to release it
int usb_mouse_buttons(uint8_t left, uint8_t middle, uint8_t right, uint8_t back, uint8_t forward)
{
uint8_t mask=0;

if (left) mask |= 1;
if (middle) mask |= 4;
if (right) mask |= 2;
if (back) mask |= 8;
if (forward) mask |= 16;
usb_mouse_buttons_state = mask;
return usb_mouse_move(0, 0, 0, 0);
}


static uint8_t transmit_previous_timeout=0;

// When the PC isn't listening, how long do we wait before discarding data?
#define TX_TIMEOUT_MSEC 30

static int usb_mouse_transmit(const uint8_t *data, uint32_t len)
{
if (!usb_configuration) return -1;
uint32_t head = tx_head;
transfer_t *xfer = tx_transfer + head;
uint32_t wait_begin_at = systick_millis_count;
while (1) {
uint32_t status = usb_transfer_status(xfer);
if (!(status & 0x80)) {
if (status & 0x68) {
// TODO: what if status has errors???
printf("ERROR status = %x, i=%d, ms=%u\n",
status, tx_head, systick_millis_count);
}
transmit_previous_timeout = 0;
break;
}
if (transmit_previous_timeout) return -1;
if (systick_millis_count - wait_begin_at > TX_TIMEOUT_MSEC) {
// waited too long, assume the USB host isn't listening
transmit_previous_timeout = 1;
return -1;
}
if (!usb_configuration) return -1;
yield();
}
uint8_t *buffer = txbuffer + head * TX_BUFSIZE;
memcpy(buffer, data, len);
usb_prepare_transfer(xfer, buffer, len, 0);
arm_dcache_flush_delete(buffer, TX_BUFSIZE);
usb_transmit(MOUSE_ENDPOINT, xfer);
if (++head >= TX_NUM) head = 0;
tx_head = head;
return 0;
}


// Move the mouse. x, y and wheel are -127 to 127. Use 0 for no movement.
int usb_mouse_move(int8_t x, int8_t y, int8_t wheel, int8_t horiz)
{
//printf("move\n");
if (x == -128) x = -127;
if (y == -128) y = -127;
if (wheel == -128) wheel = -127;
if (horiz == -128) horiz = -127;

uint8_t buffer[6];
buffer[0] = 1;
buffer[1] = usb_mouse_buttons_state;
buffer[2] = x;
buffer[3] = y;
buffer[4] = wheel;
buffer[5] = horiz; // horizontal scroll
return usb_mouse_transmit(buffer, 6);
}

int usb_mouse_position(uint16_t x, uint16_t y)
{
if (x >= usb_mouse_resolution_x) x = usb_mouse_resolution_x - 1;
usb_mouse_position_x = x;
if (y >= usb_mouse_resolution_y) y = usb_mouse_resolution_y - 1;
usb_mouse_position_y = y;
uint8_t buffer[5];
buffer[0] = 2;
uint32_t val32 = usb_mouse_position_x * usb_mouse_scale_x + usb_mouse_offset_x;
//printf("position: %u -> %u", usb_mouse_position_x, val32);
buffer[1] = val32 >> 16;
buffer[2] = val32 >> 24;
val32 = usb_mouse_position_y * usb_mouse_scale_y + usb_mouse_offset_y;
//printf(", %u -> %u\n", usb_mouse_position_y, val32);
buffer[3] = val32 >> 16;
buffer[4] = val32 >> 24;
return usb_mouse_transmit(buffer, 5);
}

void usb_mouse_screen_size(uint16_t width, uint16_t height, uint8_t mac)
{
if (width < 128) width = 128;
else if (width > 7680) width = 7680;
if (height < 128) height = 128;
else if (height > 7680) height = 7680;
usb_mouse_resolution_x = width;
usb_mouse_resolution_y = height;
usb_mouse_position_x = width / 2;
usb_mouse_position_y = height / 2;
usb_mouse_scale_x = (0x80000000ul + (width >> 1)) / width;
usb_mouse_scale_y = (0x80000000ul + (height >> 1)) / height;
usb_mouse_offset_x = (usb_mouse_scale_x >> 1) - 1;
usb_mouse_offset_y = (usb_mouse_scale_y >> 1) - 1;
if (mac) {
// ugly workaround for Mac's HID coordinate scaling:
// http://lists.apple.com/archives/usb/2011/Jun/msg00032.html
usb_mouse_offset_x += 161061273ul;
usb_mouse_offset_y += 161061273ul;
usb_mouse_scale_x = (1825361101ul + (width >> 1)) / width;
usb_mouse_scale_y = (1825361101ul + (height >> 1)) / height;
}
}


#endif // MOUSE_INTERFACE

+ 111
- 0
teensy4/usb_mouse.h View File

@@ -0,0 +1,111 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2017 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef USBmouse_h_
#define USBmouse_h_

#include "usb_desc.h"

#if defined(MOUSE_INTERFACE)

#include <inttypes.h>

// C language implementation
#ifdef __cplusplus
extern "C" {
#endif
void usb_mouse_configure(void);
int usb_mouse_buttons(uint8_t left, uint8_t middle, uint8_t right, uint8_t back, uint8_t forward);
int usb_mouse_move(int8_t x, int8_t y, int8_t wheel, int8_t horiz);
int usb_mouse_position(uint16_t x, uint16_t y);
void usb_mouse_screen_size(uint16_t width, uint16_t height, uint8_t mac);
extern uint8_t usb_mouse_buttons_state;
extern volatile uint8_t usb_configuration;
#ifdef __cplusplus
}
#endif


#define MOUSE_LEFT 1
#define MOUSE_MIDDLE 4
#define MOUSE_RIGHT 2
#define MOUSE_BACK 8
#define MOUSE_FORWARD 16
#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE | MOUSE_BACK | MOUSE_FORWARD)

// C++ interface
#ifdef __cplusplus
class usb_mouse_class
{
public:
void begin(void) { }
void end(void) { }
void move(int8_t x, int8_t y, int8_t wheel=0, int8_t horiz=0) {
usb_mouse_move(x, y, wheel, horiz);
}
void moveTo(uint16_t x, uint16_t y) { usb_mouse_position(x, y); }
void screenSize(uint16_t width, uint16_t height, bool isMacintosh = false) {
usb_mouse_screen_size(width, height, isMacintosh ? 1 : 0);
}
void click(uint8_t b = MOUSE_LEFT) {
usb_mouse_buttons_state = b;
usb_mouse_move(0, 0, 0, 0);
usb_mouse_buttons_state = 0;
usb_mouse_move(0, 0, 0, 0);
}
void scroll(int8_t wheel, int8_t horiz=0) { usb_mouse_move(0, 0, wheel, horiz); }
void set_buttons(uint8_t left, uint8_t middle=0, uint8_t right=0, uint8_t back=0, uint8_t forward=0) {
usb_mouse_buttons(left, middle, right, back, forward);
}
void press(uint8_t b = MOUSE_LEFT) {
uint8_t buttons = usb_mouse_buttons_state | (b & MOUSE_ALL);
if (buttons != usb_mouse_buttons_state) {
usb_mouse_buttons_state = buttons;
usb_mouse_move(0, 0, 0, 0);
}
}
void release(uint8_t b = MOUSE_LEFT) {
uint8_t buttons = usb_mouse_buttons_state & ~(b & MOUSE_ALL);
if (buttons != usb_mouse_buttons_state) {
usb_mouse_buttons_state = buttons;
usb_mouse_move(0, 0, 0, 0);
}
}
bool isPressed(uint8_t b = MOUSE_ALL) {
return ((usb_mouse_buttons_state & (b & MOUSE_ALL)) != 0);
}
};
extern usb_mouse_class Mouse;

#endif // __cplusplus

#endif // MOUSE_INTERFACE

#endif // USBmouse_h_

Loading…
Cancel
Save