//=============================================================================
// Simple test viewer app for several of the USB devices on ili9341 display
//
// Currently requires the libraries
// ili9341_t3n that can be located: https://github.com/KurtE/ILI9341_t3n
// spin: https://github.com/KurtE/SPIN
//
// Teensy 3.6 Pins
// 8 = RST
// 9 = D/C
// 10 = CS
//
// Teensy 4.0 Beta Pins
// 23 = RST (Marked MCLK on T4 beta breakout)
// 10 = CS (Marked CS)
// 9 = DC (Marked MEMCS)
//
// This example is in the public domain
//=============================================================================
#include "USBHost_t36.h"
#include <ili9341_t3n_font_Arial.h>
#define TEENSY64
//=============================================================================
// Connection configuration of ILI9341 LCD TFT
//=============================================================================
DMAMEM uint16_t frame_buffer[ILI9341_TFTWIDTH * ILI9341_TFTHEIGHT];
#if defined(__MK66FX1M0__) && !defined(TEENSY64)
#define TFT_RST 255
#define TFT_DC 20
#define TFT_CS 21
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST);
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
// On Teensy 4 beta with Paul's breakout out:
// Using pins (MOSI, MISO, SCK which are labeled on Audio board breakout location
// which are not in the Normal processor positions
// Also DC=10(CS), CS=9(BCLK) and RST 23(MCLK)
#define TFT_RST 23
#define TFT_DC 9
#define TFT_CS 10
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST);
#elif defined(TEENSY64)
#define TFT_RST 255
#define TFT_DC 20
#define TFT_CS 21
#define TFT_SCK 14
#define TFT_MISO 39
#define TFT_MOSI 28
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);
#else
#error "This example App will only work with Teensy 3.6 or Teensy 4."
#endif
//=============================================================================
// USB Host Ojbects
//=============================================================================
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHIDParser hid1(myusb);
USBHIDParser hid2(myusb);
JoystickController joystick1(myusb);
JoystickController joystick2(myusb);
//BluetoothController bluet(myusb, true, "0000"); // Version does pairing to device
BluetoothController bluet(myusb); // version assumes it already was paired
// Lets only include in the lists The most top level type devices we wish to show information for.
USBDriver *drivers[] = {&joystick1, &joystick2, &bluet, &hid1, &hid2};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
const char * driver_names[CNT_DEVICES] = {"Joystick1(device)", "Joystick2(device)", "Bluet", "HID1" , "HID2"};
bool driver_active[CNT_DEVICES] = {false, false, false, false};
// Lets also look at HID Input devices
USBHIDInput *hiddrivers[] = {&joystick1, &joystick2};
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
const char * hid_driver_names[CNT_HIDDEVICES] = {"joystick1", "joystick2"};
bool hid_driver_active[CNT_HIDDEVICES] = {false};
BTHIDInput *bthiddrivers[] = {&joystick1, &joystick2};
#define CNT_BTHIDDEVICES (sizeof(bthiddrivers)/sizeof(bthiddrivers[0]))
const char * bthid_driver_names[CNT_HIDDEVICES] = {"joystick1", "joystick2"};
bool bthid_driver_active[CNT_HIDDEVICES] = {false};
//=============================================================================
// Other state variables.
//=============================================================================
// Save away values for buttons, x, y, wheel
typedef struct {
uint32_t buttons_cur = 0;
int x = 0,
y = 0,
x2 = 0,
y2 = 0,
L1 = 0,
R1 = 0;
int wheel = 0;
int axis[64];
uint32_t buttons_prev = 0;
uint32_t buttons;
uint8_t left_trigger_value = 0;
uint8_t right_trigger_value = 0;
} joystick_save_data_t;
joystick_save_data_t joy_data[2];
elapsedMillis heartbeat;
uint8_t heartbeat_index = 99;
static const uint8_t heartbeat_chars[] = {'-', '/', '|', '\\'};
bool show_changed_only = false;
bool new_device_detected = false;
int16_t y_position_after_device_info = 0;
uint64_t joystick_full_notify_mask = (uint64_t) - 1;
//=============================================================================
// function declares
//=============================================================================
extern void ProcessJoystickData(JoystickController &joy, joystick_save_data_t &jsdata, uint16_t x_disp);
//=============================================================================
// Setup
//=============================================================================
void setup()
{
Serial1.begin(2000000);
while (!Serial && millis() < 3000) ; // wait for Arduino Serial Monitor
Serial.println("\n\nUSB Host multiple joystick Testing");
myusb.begin();
tft.begin();
// explicitly set the frame buffer
tft.setFrameBuffer(frame_buffer);
delay(100);
tft.setRotation(3); // 180
delay(100);
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_YELLOW);
tft.setTextSize(2);
tft.println("Waiting for Device...");
tft.useFrameBuffer(true);
heartbeat = 0;
}
#define JOYSTICK_DATA_X1 75
#define JOYSTICK_DATA_X2 175
//=============================================================================
// Loop
//=============================================================================
void loop()
{
myusb.Task();
// Update the display with
UpdateActiveDeviceInfo();
// And joystick data
ProcessJoystickData(joystick1, joy_data[0], JOYSTICK_DATA_X1);
ProcessJoystickData(joystick2, joy_data[1], JOYSTICK_DATA_X2);
if (heartbeat > 250) {
heartbeat = 0;
if (++heartbeat_index > sizeof(heartbeat_chars)) heartbeat_index = 0;
tft.setCursor(tft.width() - 10, tft.height() - 10);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.setFont(Arial_12);
tft.write(heartbeat_chars[heartbeat_index]);
tft.updateScreen();
}
}
//=============================================================================
// UpdateActiveDeviceInfo
//=============================================================================
//=============================================================================
// UpdateActiveDeviceInfo
//=============================================================================
void UpdateActiveDeviceInfo() {
// First see if any high level devices
for (uint8_t i = 0; i < CNT_DEVICES; i++) {
if (*drivers[i] != driver_active[i]) {
if (driver_active[i]) {
Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]);
driver_active[i] = false;
} else {
new_device_detected = true;
Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct());
driver_active[i] = true;
tft.fillScreen(ILI9341_BLACK); // clear the screen.
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_YELLOW);
tft.setFont(Arial_12);
tft.printf("Device %s %x:%x\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct());
const uint8_t *psz = drivers[i]->manufacturer();
if (psz && *psz) tft.printf(" manufacturer: %s\n", psz);
psz = drivers[i]->product();
if (psz && *psz) tft.printf(" product: %s\n", psz);
psz = drivers[i]->serialNumber();
if (psz && *psz) tft.printf(" Serial: %s\n", psz);
tft.updateScreen(); // update the screen now
}
}
}
// Then Hid Devices
for (uint8_t i = 0; i < CNT_HIDDEVICES; i++) {
if (*hiddrivers[i] != hid_driver_active[i]) {
if (hid_driver_active[i]) {
Serial.printf("*** HID Device %s - disconnected ***\n", hid_driver_names[i]);
hid_driver_active[i] = false;
} else {
new_device_detected = true;
Serial.printf("*** HID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct());
hid_driver_active[i] = true;
tft.fillScreen(ILI9341_BLACK); // clear the screen.
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_YELLOW);
tft.setFont(Arial_12);
tft.printf("HID Device %s %x:%x\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct());
const uint8_t *psz = hiddrivers[i]->manufacturer();
if (psz && *psz) tft.printf(" manufacturer: %s\n", psz);
psz = hiddrivers[i]->product();
if (psz && *psz) tft.printf(" product: %s\n", psz);
psz = hiddrivers[i]->serialNumber();
if (psz && *psz) tft.printf(" Serial: %s\n", psz);
tft.updateScreen(); // update the screen now
}
}
}
// Then Bluetooth devices
for (uint8_t i = 0; i < CNT_BTHIDDEVICES; i++) {
if (*bthiddrivers[i] != bthid_driver_active[i]) {
if (bthid_driver_active[i]) {
Serial.printf("*** BTHID Device %s - disconnected ***\n", hid_driver_names[i]);
bthid_driver_active[i] = false;
} else {
new_device_detected = true;
Serial.printf("*** BTHID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct());
bthid_driver_active[i] = true;
tft.fillScreen(ILI9341_BLACK); // clear the screen.
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_YELLOW);
tft.setFont(Arial_12);
tft.printf("Bluetooth Device %s %x:%x\n", bthid_driver_names[i], bthiddrivers[i]->idVendor(), bthiddrivers[i]->idProduct());
const uint8_t *psz = bthiddrivers[i]->manufacturer();
if (psz && *psz) tft.printf(" manufacturer: %s\n", psz);
psz = bthiddrivers[i]->product();
if (psz && *psz) tft.printf(" product: %s\n", psz);
psz = bthiddrivers[i]->serialNumber();
if (psz && *psz) tft.printf(" Serial: %s\n", psz);
tft.updateScreen(); // update the screen now
int16_t x;
tft.getCursor(&x, &y_position_after_device_info);
}
}
}
}
//=============================================================================
// OutputNumberField
//=============================================================================
void OutputNumberField(int16_t x, int16_t y, int val, int16_t field_width) {
int16_t x2, y2;
tft.setCursor(x, y);
tft.print(val, DEC); tft.getCursor(&x2, &y2);
tft.fillRect(x2, y, field_width - (x2 - x), Arial_12.line_space, ILI9341_BLACK);
}
//=============================================================================
// ProcessJoystickData
//=============================================================================
void ProcessJoystickData(JoystickController &joy, joystick_save_data_t &jsdata, uint16_t x_disp) {
if (joy.available()) {
uint64_t axis_mask = joy.axisMask();
uint64_t axis_changed_mask = joy.axisChangedMask();
Serial.print("Joystick: buttons = ");
jsdata.buttons = joy.getButtons();
Serial.print(jsdata.buttons, HEX);
//Serial.printf(" AMasks: %x %x:%x", axis_mask, (uint32_t)(user_axis_mask >> 32), (uint32_t)(user_axis_mask & 0xffffffff));
//Serial.printf(" M: %lx %lx", axis_mask, joy.axisChangedMask());
if (show_changed_only) {
for (uint8_t i = 0; axis_changed_mask != 0; i++, axis_changed_mask >>= 1) {
if (axis_changed_mask & 1) {
Serial.printf(" %d:%d", i, joy.getAxis(i));
}
}
} else {
for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) {
if (axis_mask & 1) {
Serial.printf(" %d:%d", i, joy.getAxis(i));
}
}
}
for (uint8_t i = 0; i < 64; i++) {
jsdata.axis[i] = joy.getAxis(i);
}
uint8_t ltv;
uint8_t rtv;
switch (joy.joystickType()) {
default:
break;
case JoystickController::PS4:
ltv = joy.getAxis(3);
rtv = joy.getAxis(4);
if ((ltv != jsdata.left_trigger_value) || (rtv != jsdata.right_trigger_value)) {
jsdata.left_trigger_value = ltv;
jsdata.right_trigger_value = rtv;
joy.setRumble(ltv, rtv);
}
break;
case JoystickController::PS3:
ltv = joy.getAxis(18);
rtv = joy.getAxis(19);
if ((ltv != jsdata.left_trigger_value) || (rtv != jsdata.right_trigger_value)) {
jsdata.left_trigger_value = ltv;
jsdata.right_trigger_value = rtv;
joy.setRumble(ltv, rtv, 50);
}
break;
case JoystickController::PS3_MOTION:
ltv = joy.getAxis(18);
rtv = joy.getAxis(19);
if ((ltv != jsdata.left_trigger_value) || (rtv != jsdata.right_trigger_value)) {
jsdata.left_trigger_value = ltv;
jsdata.right_trigger_value = rtv;
joy.setRumble(ltv, rtv, 50);
}
break;
case JoystickController::XBOXONE:
case JoystickController::XBOX360:
ltv = joy.getAxis(4);
rtv = joy.getAxis(5);
if ((ltv != jsdata.left_trigger_value) || (rtv != jsdata.right_trigger_value)) {
jsdata.left_trigger_value = ltv;
jsdata.right_trigger_value = rtv;
joy.setRumble(ltv, rtv);
Serial.printf(" Set Rumble %d %d", ltv, rtv);
}
break;
}
if (jsdata.buttons != jsdata.buttons_cur) {
if (joy.joystickType() == JoystickController::PS3) {
joy.setLEDs((jsdata.buttons >> 12) & 0xf); // try to get to TRI/CIR/X/SQuare
} else {
uint8_t lr = (jsdata.buttons & 1) ? 0xff : 0;
uint8_t lg = (jsdata.buttons & 2) ? 0xff : 0;
uint8_t lb = (jsdata.buttons & 4) ? 0xff : 0;
joy.setLEDs(lr, lg, lb);
}
jsdata.buttons_cur = jsdata.buttons;
}
Serial.println();
tft_JoystickData(joy, jsdata, x_disp);
joy.joystickDataClear();
}
}
//=============================================================================
// TFT_joystick
//=============================================================================
void tft_JoystickData(JoystickController &joy, joystick_save_data_t &jsdata, uint16_t x_disp) {
if (new_device_detected) {
// Lets display the titles.
// tft.getCursor(&x, &y_position_after_device_info);
tft.setCursor(0,y_position_after_device_info);
tft.setTextColor(ILI9341_YELLOW);
tft.printf("Buttons:\nX:\nY:\nX2\nY2(Z):\nL1:\nR1:\nHAT:");
new_device_detected = false;
}
bool something_changed = false;
if (jsdata.buttons != jsdata.buttons_prev) { //buttons
something_changed = true;
jsdata.buttons_prev = jsdata.buttons;
}
if (jsdata.axis[0] != jsdata.x) { //xL
jsdata.x = jsdata.axis[0];
something_changed = true;
}
if (jsdata.axis[1] != jsdata.y) { //yL
jsdata.y = jsdata.axis[1];
something_changed = true;
}
if (jsdata.axis[9] != jsdata.wheel) { //Hat
jsdata.wheel = jsdata.axis[9];
something_changed = true;
}
//Second Axis
if (jsdata.axis[2] != jsdata.x2) { //xR
jsdata.x2 = jsdata.axis[2];
something_changed = true;
}
if (jsdata.axis[5] != jsdata.y2) { //yR or z-axis
jsdata.y2 = jsdata.axis[5];
something_changed = true;
}
//Rumble Axis
switch (joy.joystickType()) {
case JoystickController::XBOXONE:
case JoystickController::XBOX360:
case JoystickController::PS4:
if (jsdata.axis[3] != jsdata.L1) { //xR
jsdata.L1 = jsdata.axis[3];
something_changed = true;
}
if (jsdata.axis[4] != jsdata.R1) { //yR or z-axis
jsdata.R1 = jsdata.axis[4];
something_changed = true;
}
break;
case JoystickController::PS3:
if (jsdata.axis[18] != jsdata.L1) { //xR
jsdata.L1 = jsdata.axis[18];
something_changed = true;
}
if (jsdata.axis[19] != jsdata.R1) { //yR or z-axis
jsdata.R1 = jsdata.axis[19];
something_changed = true;
}
break;
}
if (something_changed) {
int16_t x, y2;
unsigned char line_space = Arial_12.line_space;
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
//tft.setTextDatum(BR_DATUM);
int16_t y = y_position_after_device_info;
tft.setCursor(x_disp, y);
tft.printf("%d(%x)", jsdata.buttons, jsdata.buttons);
tft.getCursor(&x, &y2);
tft.fillRect(x, y, 320, line_space, ILI9341_BLACK);
y += line_space; OutputNumberField(x_disp, y, jsdata.x, 100); //x
y += line_space; OutputNumberField(x_disp, y, jsdata.y, 100); //y
y += line_space; OutputNumberField(x_disp, y, jsdata.x2, 100); //x2(z)
y += line_space; OutputNumberField(x_disp, y, jsdata.y2, 100); //y2
switch (joy.joystickType()) {
case JoystickController::PS4:
case JoystickController::PS3:
case JoystickController::XBOXONE:
case JoystickController::XBOX360:
y += line_space; OutputNumberField(x_disp, y, jsdata.L1, 100);
y += line_space; OutputNumberField(x_disp, y, jsdata.R1, 100);
break;
default:
y += line_space; OutputNumberField(x_disp, y, 0, 100);
y += line_space; OutputNumberField(x_disp, y, 0, 100);
y += line_space; OutputNumberField(x_disp, y, jsdata.wheel, 100); //hat
break;
}
tft.updateScreen(); // update the screen now
}
}