mirror of
https://github.com/mnzlmstr/N64toiQue
synced 2024-11-23 17:52:16 -05:00
created src folder, included precompiled binaries
This commit is contained in:
parent
7c272f7a90
commit
75729b083b
@ -20,3 +20,9 @@ As Timing is very critical (a bit read from the controller takes only 4uS !) I d
|
||||
|
||||
Yes you will have to edit the Pins used in the file `PinMappings.h` to match the Pins you wired everything up with. The Axis pins have to be connected to the correct Wires coming from the Joystick. For that is adviced to cut the Joystick cable in half and connect the X-Axis pins to the pins labeled 1 & 4 of the Joystick PCB and the Y-Axis pins to the pins labeled 5 & 6.
|
||||
|
||||
### Changelog:
|
||||
|
||||
13.04.2020:
|
||||
- moved source code to `src` folder
|
||||
- added precompiled binaries for Heltec WiFi LoRa 32 V2 to folder `bin`
|
||||
|
||||
|
BIN
bin/iQue.ino.heltec_wifi_lora_32_V2.bin
Normal file
BIN
bin/iQue.ino.heltec_wifi_lora_32_V2.bin
Normal file
Binary file not shown.
206
src/ControllerBuffer.cpp
Normal file
206
src/ControllerBuffer.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
#include "ControllerBuffer.h"
|
||||
#include "PinMappings.h"
|
||||
#include "Debug.h"
|
||||
|
||||
// buffer to hold data being read from controller
|
||||
bool buffer[DATA_SIZE + DATA_OFFSET];
|
||||
|
||||
// bit resolution and offsets
|
||||
int bitOffsets[32];
|
||||
int bitResolution;
|
||||
|
||||
/** Function to send a Command to the attached N64-Controller.
|
||||
* Must be run from RAM to defy timing differences introduced from
|
||||
* reading Code from ESP32's SPI Flash Chip.
|
||||
*/
|
||||
void IRAM_ATTR sendCommand(byte command)
|
||||
{
|
||||
// the current bit to write
|
||||
bool bit;
|
||||
|
||||
// clear output buffer
|
||||
memset(buffer,0,DATA_SIZE + DATA_OFFSET);
|
||||
|
||||
// for each bit
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// get value
|
||||
bit = (1 << (7 - i)) & command;
|
||||
|
||||
// write data
|
||||
LINE_WRITE_LOW;
|
||||
delayMicroseconds((3 - 2 * bit));
|
||||
LINE_WRITE_HIGH;
|
||||
delayMicroseconds((1 + 2 * bit));
|
||||
}
|
||||
|
||||
// console stop bit
|
||||
LINE_WRITE_LOW;
|
||||
delayMicroseconds(1);
|
||||
LINE_WRITE_HIGH;
|
||||
delayMicroseconds(2);
|
||||
|
||||
// read returned data as fast as possible
|
||||
for(int i = 0;i < DATA_SIZE + DATA_OFFSET;i++)
|
||||
{
|
||||
buffer[i] = digitalRead(DATA_PIN);
|
||||
}
|
||||
|
||||
// plot polling process from controller if unstructed to
|
||||
#ifdef PLOT_CONSOLE_POLLING
|
||||
for(int i = 0; i < DATA_SIZE + DATA_OFFSET;i++)
|
||||
{
|
||||
Serial.println(buffer[i]*2500);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Function to extract a controller bit from the buffer of returned data */
|
||||
void getBit(bool *bit,int offset,bool *data)
|
||||
{
|
||||
// sanity check offset
|
||||
if(offset < 0) offset = 0;
|
||||
|
||||
// count
|
||||
short count = 0;
|
||||
|
||||
// get count from offset to offset + length
|
||||
for(int i = offset + DATA_OFFSET;i < offset + bitResolution;i++)
|
||||
{
|
||||
count += *(data + i);
|
||||
}
|
||||
|
||||
// if offset surpasses threshold set bit
|
||||
*bit = false;
|
||||
if(count > BIT_THRESHOLD) *bit = true;
|
||||
}
|
||||
|
||||
/** Function to populate the controller struct if command 0x01 was sent.
|
||||
* Buttons are set according to data in buffer, raw axis data is written,
|
||||
* Axis Data is correctly decoded from raw axis data by taking two's complement
|
||||
* and checking if value if below 'MAX_INCLINE_AXIS_X' or 'MAX_INCLINE_AXIS_Y'.
|
||||
* If values surpass the maximum incline they are set to match those values.
|
||||
*/
|
||||
void populateControllerStruct(ControllerData *data)
|
||||
{
|
||||
// first byte
|
||||
getBit(&(data->buttonA) , bitOffsets[0] ,&buffer[0]);
|
||||
getBit(&(data->buttonB), bitOffsets[1] ,&buffer[0]);
|
||||
getBit(&(data->buttonZ), bitOffsets[2] ,&buffer[0]);
|
||||
getBit(&(data->buttonStart), bitOffsets[3] ,&buffer[0]);
|
||||
getBit(&(data->DPadUp), bitOffsets[4] ,&buffer[0]);
|
||||
getBit(&(data->DPadDown), bitOffsets[5] ,&buffer[0]);
|
||||
getBit(&(data->DPadLeft), bitOffsets[6] ,&buffer[0]);
|
||||
getBit(&(data->DPadRight), bitOffsets[7] ,&buffer[0]);
|
||||
|
||||
// second byte, first two bits are unused
|
||||
getBit(&(data->buttonL), bitOffsets[10] ,&buffer[0]);
|
||||
getBit(&(data->buttonR), bitOffsets[11] ,&buffer[0]);
|
||||
getBit(&(data->CUp), bitOffsets[12] ,&buffer[0]);
|
||||
getBit(&(data->CDown), bitOffsets[13] ,&buffer[0]);
|
||||
getBit(&(data->CLeft), bitOffsets[14] ,&buffer[0]);
|
||||
getBit(&(data->CRight), bitOffsets[15] ,&buffer[0]);
|
||||
|
||||
// third byte
|
||||
getBit(&(data->xAxisRaw[0]), bitOffsets[16], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[1]), bitOffsets[17], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[2]), bitOffsets[18], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[3]), bitOffsets[19], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[4]), bitOffsets[20], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[5]), bitOffsets[21], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[6]), bitOffsets[22], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[7]), bitOffsets[23], &buffer[0]);
|
||||
|
||||
// fourth byte
|
||||
getBit(&(data->yAxisRaw[0]), bitOffsets[24], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[1]), bitOffsets[25], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[2]), bitOffsets[26], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[3]), bitOffsets[27], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[4]), bitOffsets[28], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[5]), bitOffsets[29], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[6]), bitOffsets[30], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[7]), bitOffsets[31], &buffer[0]);
|
||||
|
||||
// sum up bits to get axis bytes
|
||||
data->xAxis = 0;
|
||||
data->yAxis = 0;
|
||||
for(int i = 0;i < 8;i++)
|
||||
{
|
||||
data->xAxis += (data->xAxisRaw[i] * (0x80 >> (i)));
|
||||
data->yAxis += (data->yAxisRaw[i] * (0x80 >> (i)));
|
||||
|
||||
// print y axis values
|
||||
#ifdef PRINT_Y_AXIS_VALUES
|
||||
Serial.printf("%i %i %i %i %i %i %i %i\n",data->yAxisRaw[0],data->yAxisRaw[1],data->yAxisRaw[2],data->yAxisRaw[3],data->yAxisRaw[4],data->yAxisRaw[5],data->yAxisRaw[6],data->yAxisRaw[7]);
|
||||
Serial.printf("yAxis: %i \n",data->yAxis);
|
||||
#endif
|
||||
|
||||
// print x axis values
|
||||
#ifdef PRINT_X_AXIS_VALUES
|
||||
Serial.printf("%i %i %i %i %i %i %i %i\n",data->xAxisRaw[0],data->xAxisRaw[1],data->xAxisRaw[2],data->xAxisRaw[3],data->xAxisRaw[4],data->xAxisRaw[5],data->xAxisRaw[6],data->xAxisRaw[7]);
|
||||
Serial.printf("xAxis: %i \n",data->xAxis);
|
||||
#endif
|
||||
}
|
||||
|
||||
// decode xAxis two's complement
|
||||
if(data->xAxis & 0x80)
|
||||
{
|
||||
data->xAxis = -1 * (0xff - data->xAxis);
|
||||
}
|
||||
|
||||
// decode yAxis two's complement
|
||||
if(data->yAxis & 0x80)
|
||||
{
|
||||
data->yAxis = -1 * (0xff - data->yAxis);
|
||||
}
|
||||
|
||||
// keep x axis below maxIncline
|
||||
if(data->xAxis > MAX_INCLINE_AXIS_X) data->xAxis = MAX_INCLINE_AXIS_X;
|
||||
if(data->xAxis < -MAX_INCLINE_AXIS_X) data->xAxis = -MAX_INCLINE_AXIS_X;
|
||||
|
||||
// keep y axis below maxIncline
|
||||
if(data->yAxis > MAX_INCLINE_AXIS_Y) data->yAxis = MAX_INCLINE_AXIS_Y;
|
||||
if(data->yAxis < -MAX_INCLINE_AXIS_Y) data->yAxis = -MAX_INCLINE_AXIS_Y;
|
||||
|
||||
//Serial.printf("xaxis: %-3i yaxis: %-3i \n",data->xAxis,data->yAxis);
|
||||
}
|
||||
|
||||
void updateOffsetsAndResolution()
|
||||
{
|
||||
// the current bit counter
|
||||
int bitCounter = 0;
|
||||
|
||||
// to hold the offset of A Button's falling edge
|
||||
int bitAfallingOffset = 0;
|
||||
|
||||
// iterate over buffer
|
||||
for(int i = 0;i < DATA_SIZE + DATA_OFFSET - 1;i++)
|
||||
{
|
||||
// if a falling edge is detected
|
||||
if(buffer[i] == true && buffer[1+i] == false)
|
||||
{
|
||||
// store bit's end offset
|
||||
bitOffsets[bitCounter] = i+1;
|
||||
|
||||
// if it's the A button store offset of the falling edge
|
||||
if(bitCounter == 0) bitAfallingOffset = i+1;
|
||||
|
||||
// if it's the B button calculate the bit Resolution
|
||||
if(bitCounter == 1) bitResolution = (i+1) - bitAfallingOffset;
|
||||
|
||||
// increment bit counter
|
||||
bitCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
Serial.printf("Bit resolution is %i \n",bitResolution);
|
||||
|
||||
// calculate bit's beginning offsets by subtracting resolution
|
||||
for(int i = 0;i < 32;i++)
|
||||
{
|
||||
bitOffsets[i] -= bitResolution;
|
||||
Serial.printf("beginning of bit %i detected @ begin+%i \n",i+1,bitOffsets[i]);
|
||||
}
|
||||
|
||||
|
||||
}
|
26
src/ControllerBuffer.h
Normal file
26
src/ControllerBuffer.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef CONTROLLER_BUFFER_H
|
||||
#define CONTROLLER_BUFFER_H
|
||||
|
||||
#include "ControllerData.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#define DATA_SIZE 450 // number of sample points to poll
|
||||
#define DATA_OFFSET 0 // number of samples to ignore after staring to poll
|
||||
|
||||
#define MAX_INCLINE_AXIS_X 60
|
||||
#define MAX_INCLINE_AXIS_Y 60
|
||||
|
||||
#define BIT_THRESHOLD 6
|
||||
|
||||
extern void IRAM_ATTR sendCommand(byte command);
|
||||
extern void populateControllerStruct(ControllerData *data);
|
||||
|
||||
/** Function to read the offsets of the individual bits so that they can be updated for reading.
|
||||
* Resolution is detected by taking the distance of two falling edges of Button A and B.
|
||||
* Buttons must not be pressed by the time this command is invoked !
|
||||
* sendCommand(0x01) must be invoked before !
|
||||
*/
|
||||
extern void updateOffsetsAndResolution();
|
||||
|
||||
|
||||
#endif
|
31
src/ControllerData.h
Normal file
31
src/ControllerData.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef CONTROLLER_DATA_H
|
||||
#define CONTROLLER_DATA_H
|
||||
|
||||
struct ControllerData
|
||||
{
|
||||
bool buttonA;
|
||||
bool buttonB;
|
||||
bool buttonZ;
|
||||
bool buttonL;
|
||||
bool buttonR;
|
||||
bool buttonStart;
|
||||
|
||||
bool DPadUp;
|
||||
bool DPadDown;
|
||||
bool DPadLeft;
|
||||
bool DPadRight;
|
||||
|
||||
bool CUp;
|
||||
bool CDown;
|
||||
bool CLeft;
|
||||
bool CRight;
|
||||
|
||||
short xAxis;
|
||||
short yAxis;
|
||||
|
||||
bool xAxisRaw[8];
|
||||
bool yAxisRaw[8];
|
||||
|
||||
};
|
||||
|
||||
#endif
|
8
src/Debug.h
Normal file
8
src/Debug.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
//#define PLOT_CONSOLE_POLLING
|
||||
//#define PRINT_X_AXIS_VALUES
|
||||
//#define PRINT_Y_AXIS_VALUES
|
||||
|
||||
#endif
|
135
src/Output.cpp
Normal file
135
src/Output.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
#include "Output.h"
|
||||
#include "PinMappings.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
int encoderXpos = 0;
|
||||
int encoderYpos = 0;
|
||||
|
||||
void setupIO()
|
||||
{
|
||||
// the controller data line
|
||||
LINE_WRITE_HIGH;
|
||||
|
||||
pinMode(PIN_BUTTON_A,OUTPUT);
|
||||
pinMode(PIN_BUTTON_B,OUTPUT);
|
||||
pinMode(PIN_BUTTON_Z,OUTPUT);
|
||||
pinMode(PIN_BUTTON_S,OUTPUT);
|
||||
pinMode(PIN_BUTTON_L,OUTPUT);
|
||||
pinMode(PIN_BUTTON_R,OUTPUT);
|
||||
|
||||
pinMode(PIN_DPAD_UP, OUTPUT);
|
||||
pinMode(PIN_DPAD_DOWN, OUTPUT);
|
||||
pinMode(PIN_DPAD_LEFT, OUTPUT);
|
||||
pinMode(PIN_DPAD_RIGHT,OUTPUT);
|
||||
|
||||
pinMode(PIN_C_UP, OUTPUT);
|
||||
pinMode(PIN_C_DOWN, OUTPUT);
|
||||
pinMode(PIN_C_LEFT, OUTPUT);
|
||||
pinMode(PIN_C_RIGHT,OUTPUT);
|
||||
|
||||
pinMode(PIN_A_AXIS_X, OUTPUT);
|
||||
pinMode(PIN_B_AXIS_X, OUTPUT);
|
||||
|
||||
pinMode(PIN_A_AXIS_Y, OUTPUT);
|
||||
pinMode(PIN_B_AXIS_Y, OUTPUT);
|
||||
}
|
||||
|
||||
/** Function to simulate the 90° phaseshifted quadrature encoding used by
|
||||
* the N64-Controller's joystick's linear encoders. As only change in position
|
||||
* (not absolute position) is reported the change in the value between writes
|
||||
* is needed for calculation. Must be run from RAM to mitigate timing differences in
|
||||
* ESP32's SPI-Flash Chip Access Times.
|
||||
* @param relativeMovement should be processed by calling 'mapJoystickToEncoderPos'
|
||||
* with the read joystick position.
|
||||
*/
|
||||
void IRAM_ATTR moveAxis(int axisPinA,int axisPinB,int requestedEncoderPos,int *realEncoderPos)
|
||||
{
|
||||
// get difference from requested ender position to real encoder position
|
||||
int difference = requestedEncoderPos - *realEncoderPos;
|
||||
|
||||
// store new real encoder position
|
||||
*realEncoderPos = requestedEncoderPos;
|
||||
|
||||
// set pins used for outputting
|
||||
int pinA = axisPinA;
|
||||
int pinB = axisPinB;
|
||||
|
||||
// invert pins if moving in the other direction
|
||||
if(difference > 0)
|
||||
{
|
||||
pinA = axisPinB;
|
||||
pinB = axisPinA;
|
||||
}
|
||||
|
||||
// get absolute movement value
|
||||
difference = abs(difference);
|
||||
|
||||
// for each change in movement
|
||||
for(int i = 0;i < difference;i++)
|
||||
{
|
||||
// replicate 90° phaseshifted quadrate output
|
||||
digitalWrite(pinA,LOW);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(pinB,LOW);
|
||||
delayMicroseconds(6);
|
||||
digitalWrite(pinA,HIGH);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(pinB,HIGH);
|
||||
|
||||
// debounce as N64 will not detect change correctly otherwise
|
||||
delayMicroseconds(40);
|
||||
}
|
||||
}
|
||||
|
||||
/** Function to map Joystick position to relative Encoder Position.
|
||||
* According to Nintendo the maximum value for any axis to be assumed should
|
||||
* be +- 60. The encoder starts acting strange after ~ 30 turns in a given
|
||||
* direction. Also passing on ControllerData struct so that user specified
|
||||
* modifiers can be used to specify alternate mapping, eg. for
|
||||
* easier ESS-Position in Ocarina of Time (see my example)
|
||||
*/
|
||||
int mapJoystickToEncoderPos(int joyval,ControllerData *data)
|
||||
{
|
||||
// ESS-Modifier for Ocarina of Time, hold A+B to stay in ESS-Position
|
||||
if(data->buttonA && data->buttonB) return -2;
|
||||
|
||||
// deadzone handling
|
||||
if(abs(joyval) < 3) return 0;
|
||||
|
||||
// normally return half ???
|
||||
return (int)(joyval * .5f);
|
||||
}
|
||||
|
||||
void outputToiQue(ControllerData *data)
|
||||
{
|
||||
// ===== Write Button Data =====
|
||||
digitalWrite(PIN_BUTTON_A,data->buttonA);
|
||||
digitalWrite(PIN_BUTTON_B,data->buttonB);
|
||||
digitalWrite(PIN_BUTTON_L,data->buttonL);
|
||||
digitalWrite(PIN_BUTTON_R,data->buttonR);
|
||||
digitalWrite(PIN_BUTTON_Z,data->buttonZ);
|
||||
digitalWrite(PIN_BUTTON_S,data->buttonStart);
|
||||
|
||||
// ===== Write D-Pad Data =====
|
||||
digitalWrite(PIN_DPAD_UP, data->DPadUp);
|
||||
digitalWrite(PIN_DPAD_DOWN, data->DPadDown);
|
||||
digitalWrite(PIN_DPAD_LEFT, data->DPadLeft);
|
||||
digitalWrite(PIN_DPAD_RIGHT,data->DPadRight);
|
||||
|
||||
// ===== Write C-Button Data =====
|
||||
digitalWrite(PIN_C_UP, data->CUp);
|
||||
digitalWrite(PIN_C_DOWN, data->CDown);
|
||||
digitalWrite(PIN_C_LEFT, data->CLeft);
|
||||
digitalWrite(PIN_C_RIGHT, data->CRight);
|
||||
|
||||
// ===== Write Joystick Data =====
|
||||
|
||||
// calculate change in axis between writes
|
||||
//int xAxisChange = data->xAxis - lastxAxis;
|
||||
//int yAxisChange = data->yAxis - lastyAxis;
|
||||
|
||||
// move axis accordingly
|
||||
moveAxis(PIN_A_AXIS_X,PIN_B_AXIS_X,mapJoystickToEncoderPos(data->xAxis,data),&encoderXpos);
|
||||
moveAxis(PIN_A_AXIS_Y,PIN_B_AXIS_Y,mapJoystickToEncoderPos(data->yAxis,data),&encoderYpos);
|
||||
}
|
19
src/Output.h
Normal file
19
src/Output.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef OUTPUT_H
|
||||
#define OUTPUT_H
|
||||
|
||||
#include "ControllerData.h"
|
||||
|
||||
/** Function to output Data stored in ControllerData struct to the iQue console.
|
||||
* Buttons states are directly set usig digitalWrite(), Axis Data is written by
|
||||
* Simulating the 90° shifted quadrate encoding used by the N64 joysticks.
|
||||
* As these operate on a relative basis the difference between the current
|
||||
* and the last joystick positions are calculated and simulated.
|
||||
*/
|
||||
extern void outputToiQue(ControllerData *data);
|
||||
|
||||
/** Function to setup the IO used for interfacing with the N64-Controller
|
||||
* and the iQue-Console
|
||||
*/
|
||||
extern void setupIO();
|
||||
|
||||
#endif
|
33
src/PinMappings.h
Normal file
33
src/PinMappings.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef PIN_MAPPINGS_H
|
||||
#define PIN_MAPPINGS_H
|
||||
|
||||
#define DATA_PIN 13
|
||||
|
||||
#define PIN_BUTTON_A 15
|
||||
#define PIN_BUTTON_B 5
|
||||
#define PIN_BUTTON_Z 23
|
||||
#define PIN_BUTTON_S 1
|
||||
#define PIN_BUTTON_L 1
|
||||
#define PIN_BUTTON_R 1
|
||||
|
||||
#define PIN_DPAD_UP 1
|
||||
#define PIN_DPAD_DOWN 1
|
||||
#define PIN_DPAD_LEFT 1
|
||||
#define PIN_DPAD_RIGHT 1
|
||||
|
||||
#define PIN_C_UP 1
|
||||
#define PIN_C_DOWN 1
|
||||
#define PIN_C_LEFT 1
|
||||
#define PIN_C_RIGHT 1
|
||||
|
||||
#define PIN_A_AXIS_X 14
|
||||
#define PIN_B_AXIS_X 27
|
||||
|
||||
#define PIN_A_AXIS_Y 2
|
||||
#define PIN_B_AXIS_Y 4
|
||||
|
||||
#define LINE_WRITE_HIGH pinMode(DATA_PIN,INPUT_PULLUP)
|
||||
#define LINE_WRITE_LOW pinMode(DATA_PIN,OUTPUT)
|
||||
|
||||
|
||||
#endif
|
39
src/iQue.ino
Normal file
39
src/iQue.ino
Normal file
@ -0,0 +1,39 @@
|
||||
#include "Output.h"
|
||||
#include "ControllerData.h"
|
||||
#include "ControllerBuffer.h"
|
||||
#include "Debug.h"
|
||||
|
||||
ControllerData controller;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
// setup io pins
|
||||
setupIO();
|
||||
|
||||
#ifdef PLOT_CONSOLE_POLLING
|
||||
delay(5000);
|
||||
sendCommand(0x01);
|
||||
while(true);
|
||||
#endif
|
||||
|
||||
sendCommand(0x01);
|
||||
updateOffsetsAndResolution();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// send command 0x01 to n64 controller
|
||||
sendCommand(0x01);
|
||||
|
||||
// store received data in controller struct
|
||||
populateControllerStruct(&controller);
|
||||
|
||||
// output received data to ique
|
||||
outputToiQue(&controller);
|
||||
|
||||
// polling must not occur faster than every 20 ms
|
||||
delay(14);
|
||||
}
|
Loading…
Reference in New Issue
Block a user