Skip to content

Instantly share code, notes, and snippets.

@wackoisgod
Created February 8, 2020 07:37
Show Gist options
  • Save wackoisgod/d9bd3853d608841ca36ede0caa4df960 to your computer and use it in GitHub Desktop.
Save wackoisgod/d9bd3853d608841ca36ede0caa4df960 to your computer and use it in GitHub Desktop.
#include "Joystick.h"
#include <stdio.h>
#include <stdlib.h>
typedef enum {
UP,
DOWN,
LEFT,
RIGHT,
UP_LEFT,
UP_RIGHT,
DOWN_LEFT,
DOWN_RIGHT,
RIGHT_BUTTON,
DOWN_BUTTON,
LEFT_BUTTON,
UP_BUTTON,
X,
Y,
A,
B,
L,
R,
PLUS,
MINUS,
HOME,
NOTHING
} Buttons_t;
typedef struct {
Buttons_t button;
uint16_t duration;
} command;
struct inputArray {
command* data;
int len;
};
static struct inputArray input;
void repeat(Buttons_t button, uint16_t duration, int countToAdd, int nothingDuration, struct inputArray* array)
{
int finalAmount = array->len + countToAdd * 2;
do
{
command f = { button, duration };
array->data[array->len] = f;
array->len++;
if (nothingDuration != 0)
{
command n = { NOTHING, nothingDuration };
array->data[array->len] = n;
array->len++;
}
} while (array->len < finalAmount);
}
const int totalArraySize = 100;
void setupSteps()
{
input.len = 0;
input.data = (command*)(malloc(totalArraySize * sizeof(command)));
memset(input.data, 0, sizeof(command) * totalArraySize);
}
// Main entry point.
int main(void) {
setupSteps();
// We'll start by performing hardware and peripheral setup.
SetupHardware();
// We'll then enable global interrupts for our use.
GlobalInterruptEnable();
// Once that's done, we'll enter an infinite loop.
for (;;)
{
// We need to run our task to process and deliver data for our IN and OUT endpoints.
HID_Task();
// We also need to run the main USB management task.
USB_USBTask();
}
}
// Configures hardware and peripherals, such as the USB peripherals.
void SetupHardware(void) {
// We need to disable watchdog if enabled by bootloader/fuses.
MCUSR &= ~(1 << WDRF);
wdt_disable();
// We need to disable clock division before initializing the USB hardware.
clock_prescale_set(clock_div_1);
// We can then initialize our hardware and peripherals, including the USB stack.
#ifdef ALERT_WHEN_DONE
// Both PORTD and PORTB will be used for the optional LED flashing and buzzer.
#warning LEDand Buzzer functionality enabled.All pins on both PORTBand \
PORTD will toggle when printing is done.
DDRD = 0xFF; //Teensy uses PORTD
PORTD = 0x0;
//We'll just flash all pins on both ports since the UNO R3
DDRB = 0xFF; //uses PORTB. Micro can use either or, but both give us 2 LEDs
PORTB = 0x0; //The ATmega328P on the UNO will be resetting, so unplug it?
#endif
// The USB stack should be initialized last.
USB_Init();
}
// Fired to indicate that the device is enumerating.
void EVENT_USB_Device_Connect(void) {
// We can indicate that we're enumerating here (via status LEDs, sound, etc.).
}
// Fired to indicate that the device is no longer connected to a host.
void EVENT_USB_Device_Disconnect(void) {
// We can indicate that our device is not ready (via status LEDs, sound, etc.).
}
// Fired when the host set the current configuration of the USB device after enumeration.
void EVENT_USB_Device_ConfigurationChanged(void) {
bool ConfigSuccess = true;
// We setup the HID report endpoints.
ConfigSuccess &= Endpoint_ConfigureEndpoint(JOYSTICK_OUT_EPADDR, EP_TYPE_INTERRUPT, JOYSTICK_EPSIZE, 1);
ConfigSuccess &= Endpoint_ConfigureEndpoint(JOYSTICK_IN_EPADDR, EP_TYPE_INTERRUPT, JOYSTICK_EPSIZE, 1);
// We can read ConfigSuccess to indicate a success or failure at this point.
}
// Process control requests sent to the device from the USB host.
void EVENT_USB_Device_ControlRequest(void) {
// We can handle two control requests: a GetReport and a SetReport.
// Not used here, it looks like we don't receive control request from the Switch.
}
// Process and deliver data from IN and OUT endpoints.
void HID_Task(void) {
// If the device isn't connected and properly configured, we can't do anything here.
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
// We'll start with the OUT endpoint.
Endpoint_SelectEndpoint(JOYSTICK_OUT_EPADDR);
// We'll check to see if we received something on the OUT endpoint.
if (Endpoint_IsOUTReceived())
{
// If we did, and the packet has data, we'll react to it.
if (Endpoint_IsReadWriteAllowed())
{
// We'll create a place to store our data received from the host.
USB_JoystickReport_Output_t JoystickOutputData;
// We'll then take in that data, setting it up in our storage.
while (Endpoint_Read_Stream_LE(&JoystickOutputData, sizeof(JoystickOutputData), NULL) != ENDPOINT_RWSTREAM_NoError);
// At this point, we can react to this data.
// However, since we're not doing anything with this data, we abandon it.
}
// Regardless of whether we reacted to the data, we acknowledge an OUT packet on this endpoint.
Endpoint_ClearOUT();
}
// We'll then move on to the IN endpoint.
Endpoint_SelectEndpoint(JOYSTICK_IN_EPADDR);
// We first check to see if the host is ready to accept data.
if (Endpoint_IsINReady())
{
// We'll create an empty report.
USB_JoystickReport_Input_t JoystickInputData;
// We'll then populate this report with what we want to send to the host.
GetNextReport(&JoystickInputData);
// Once populated, we can output this data to the host. We do this by first writing the data to the control stream.
while (Endpoint_Write_Stream_LE(&JoystickInputData, sizeof(JoystickInputData), NULL) != ENDPOINT_RWSTREAM_NoError);
// We then send an IN packet on this endpoint.
Endpoint_ClearIN();
}
}
typedef enum {
SYNC_CONTROLLER,
SYNC_POSITION,
BREATHE,
PROCESS,
CIRCLE_ME,
CLEANUP,
DONE
} State_t;
State_t state = SYNC_CONTROLLER;
#define ECHOES 2
int echoes = 0;
USB_JoystickReport_Input_t last_report;
int report_count = 0;
int xpos = 0;
int ypos = 0;
int bufindex = 0;
int duration_count = 0;
int portsval = 0;
void reset_report(USB_JoystickReport_Input_t* const ReportData) {
memset(ReportData, 0, sizeof(USB_JoystickReport_Input_t));
ReportData->LX = STICK_CENTER;
ReportData->LY = STICK_CENTER;
ReportData->RX = STICK_CENTER;
ReportData->RY = STICK_CENTER;
ReportData->HAT = HAT_CENTER;
}
// Prepare the next report for the host.
void GetNextReport(USB_JoystickReport_Input_t* const ReportData) {
reset_report(ReportData);
// Repeat ECHOES times the last report
if (echoes > 0)
{
memcpy(ReportData, &last_report, sizeof(USB_JoystickReport_Input_t));
echoes--;
return;
}
// States and moves management
switch (state)
{
case SYNC_CONTROLLER:
state = BREATHE;
break;
case SYNC_POSITION:
bufindex = 0;
ReportData->Button = 0;
ReportData->LX = STICK_CENTER;
ReportData->LY = STICK_CENTER;
ReportData->RX = STICK_CENTER;
ReportData->RY = STICK_CENTER;
ReportData->HAT = HAT_CENTER;
state = BREATHE;
break;
case BREATHE:
state = CIRCLE_ME;
break;
case CIRCLE_ME:
// This is just a hack to see if this works ?
ReportData->LX = STICK_MAX;
ReportData->RX = STICK_MAX;
duration_count++;
if (duration_count % 50 >= 0 && duration_count % 50 < 5) {
ReportData->Button |= SWITCH_A;
}
if (duration_count > 10000 - 1) {
duration_count = 0;
bufindex = 0;
state = SYNC_CONTROLLER;
}
break;
case PROCESS:
switch (input.data[bufindex].button)
{
case UP:
ReportData->LY = STICK_MIN;
break;
case RIGHT_BUTTON:
ReportData->HAT = HAT_RIGHT;
break;
case LEFT_BUTTON:
ReportData->HAT = HAT_LEFT;
break;
case DOWN_BUTTON:
ReportData->HAT = HAT_BOTTOM;
break;
case UP_BUTTON:
ReportData->HAT = HAT_TOP;
break;
case LEFT:
ReportData->LX = STICK_MIN;
break;
case DOWN:
ReportData->LY = STICK_MAX;
break;
case RIGHT:
ReportData->LX = STICK_MAX;
break;
case UP_LEFT:
ReportData->LY = STICK_MIN;
ReportData->LX = STICK_MIN;
break;
case UP_RIGHT:
ReportData->LY = STICK_MIN;
ReportData->LX = STICK_MAX;
break;
case DOWN_LEFT:
ReportData->LY = STICK_MAX;
ReportData->LX = STICK_MIN;
break;
case DOWN_RIGHT:
ReportData->LY = STICK_MAX;
ReportData->LX = STICK_MAX;
break;
case A:
ReportData->Button |= SWITCH_A;
break;
case B:
ReportData->Button |= SWITCH_B;
break;
case R:
ReportData->Button |= SWITCH_R;
break;
case HOME:
ReportData->Button |= SWITCH_HOME;
break;
case X:
ReportData->Button |= SWITCH_X;
break;
case Y:
ReportData->Button |= SWITCH_Y;
break;
case PLUS:
ReportData->Button |= SWITCH_PLUS;
break;
case MINUS:
ReportData->Button |= SWITCH_MINUS;
break;
default:
ReportData->LX = STICK_CENTER;
ReportData->LY = STICK_CENTER;
ReportData->RX = STICK_CENTER;
ReportData->RY = STICK_CENTER;
ReportData->HAT = HAT_CENTER;
break;
}
duration_count++;
if (duration_count > input.data[bufindex].duration)
{
bufindex++;
duration_count = 0;
}
if (bufindex > input.len - 1)
{
bufindex = 0;
duration_count = 0;
state = BREATHE;
reset_report(ReportData)
}
break;
case CLEANUP:
state = DONE;
break;
case DONE:
#ifdef ALERT_WHEN_DONE
portsval = ~portsval;
PORTD = portsval; //flash LED(s) and sound buzzer if attached
PORTB = portsval;
_delay_ms(250);
#endif
return;
}
// // Inking
// if (state != SYNC_CONTROLLER && state != SYNC_POSITION)
// if (pgm_read_byte(&(image_data[(xpos / 8) + (ypos * 40)])) & 1 << (xpos % 8))
// ReportData->Button |= SWITCH_A;
// Prepare to echo this report
memcpy(&last_report, ReportData, sizeof(USB_JoystickReport_Input_t));
echoes = ECHOES;
}
/*
By Faiden
void repeat(Buttons_t button, uint16_t duration, int countToAdd, int delay, struct inputArray* array)
{
int finalAmount = array->len + countToAdd * 2;
do
{
command f = { button, duration };
array->data[array->len] = f;
array->len++;
command n = {NOTHING, delay};
array->data[array->len] = n;
array->len++;
} while (array->len < finalAmount);
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment