diff --git a/SD/config/settings.ini b/SD/config/settings.ini
new file mode 100644
index 0000000..44911df
--- /dev/null
+++ b/SD/config/settings.ini
@@ -0,0 +1,53 @@
+
+[hid report]
+DeviceName=RP2040-HOTAS
+enableMouse=false
+enableKeyboard=false
+UsagePage=1
+Usage=4
+ButtonCount=100
+HatCount=1
+AxisCount=4
+AxisResolution=11
+ADCResolution=11
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
+enableMouse=false
+enableKeyboard=false
+UsagePage=1
+Usage=4
+ButtonCount=64
+HatCount=1
+AxisCount=8
+AxisResolution=11
+ADCResolution=11
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SD/index.html b/SD/index.html
index 61b9e40..90a0346 100644
--- a/SD/index.html
+++ b/SD/index.html
@@ -8,7 +8,7 @@
PicoW Index page
- Pinout
+ Pinout
AJAX-testpage
diff --git a/SD/pinout/pinout.css b/SD/pinout/pinout.css
new file mode 100644
index 0000000..02941f9
--- /dev/null
+++ b/SD/pinout/pinout.css
@@ -0,0 +1,397 @@
+body {
+ display: grid;
+ place-items: center;
+ font-family: Verdana, Geneva, Tahoma, sans-serif;
+ margin: 0;
+ padding: 0;
+}
+
+article {
+ display: grid;
+ grid-template-columns: auto auto auto;
+ align-items: center;
+ margin-top: 10px;
+ padding: 0 10px;
+}
+
+footer {
+ display: grid;
+ align-items: center;
+ margin: 20px 0;
+}
+
+footer p {
+ padding: 5px 10px;
+ margin: 0;
+ text-align: center;
+}
+
+nav {
+ text-align: center;
+ margin-top: 20px;
+}
+
+header {
+ background: #002b36;
+ color: #e9e5d2;
+ display: block;
+ width: 100%;
+ line-height: 22px;
+ padding: 10px;
+ border-bottom: 5px solid #268bd2;
+ display: grid;
+ grid-template-columns: 10px auto auto 10px;
+}
+
+header h1 {
+ margin: 0;
+ padding: 0;
+ font-size: 20px;
+ grid-column: 2;
+}
+
+header ul {
+ grid-column: 3;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ text-align: right;
+}
+
+header li {
+ display: inline-block;
+ padding: 0 0 0 10px;
+ white-space: pre;
+}
+
+header li:nth-child(2) a,
+header li:nth-child(2) a:visited,
+header li:nth-child(2) a:hover {
+ color: #268bd2;
+}
+
+header li:nth-child(3) a,
+header li:nth-child(3) a:visited,
+header li:nth-child(3) a:hover {
+ color: #d33682;
+}
+
+header li:nth-child(4) a,
+header li:nth-child(4) a:visited,
+header li:nth-child(4) a:hover {
+ color: #dc322f;
+}
+
+.pico {
+ padding: 0;
+ position: relative;
+ top: -8px;
+}
+
+.labels.right {
+ counter-reset: pin 41;
+ display: grid;
+ align-items: left;
+}
+
+.tiny2040 .labels.right {
+ counter-reset: pin 17;
+}
+
+.labels.left {
+ direction: rtl;
+ display: grid;
+ align-items: right;
+}
+
+.labels tr {
+ counter-increment: pin;
+ line-height: 20px;
+ color: #333;
+ font-size: 0;
+}
+
+.labels.left tr {
+ direction: ltr;
+}
+
+.labels.right tbody tr {
+ counter-increment: pin -1;
+}
+
+.labels.below {
+ grid-column: 2;
+ margin: -5px auto 0;
+ position: relative;
+ left: 2px;
+}
+
+.labels.below td {
+ width: 23px;
+ height: auto;
+ border: none;
+ padding: 0;
+ writing-mode: sideways-lr;
+ vertical-align: top;
+}
+
+.underside-view .labels.below {
+ left: -2px;
+}
+
+.labels th,
+.labels thead {
+ display: none;
+}
+
+.labels tbody tr:before {
+ content: counter(pin);
+ text-align: center;
+ float: right;
+ background-color: #ccc;
+ width: 20px;
+ height: 20px;
+ font-size: 11px;
+}
+
+.labels.right tbody tr:before {
+ float: left;
+}
+
+.labels.below tbody tr:before {
+ display: none;
+}
+
+td,
+th {
+ height: 20px;
+ text-align: left;
+ overflow: hidden;
+ color: #222;
+ font-size: 12px;
+ cursor: default;
+ white-space: nowrap;
+ position: relative;
+ border-width: 0 4px;
+ border-style: solid;
+ padding: 0 8px;
+}
+
+.extra td {
+ border: none;
+ background-color: #9e9d9b33;
+}
+
+.extra th {
+ border: none;
+ background-color: transparent;
+}
+
+.labels .advanced {
+ visibility: hidden;
+}
+
+.labels .hidden,
+.extra.advanced,
+.below.advanced {
+ display: none;
+}
+
+.filter li.advanced {
+ display: none;
+}
+
+.gpio {
+ background-color: #85990033;
+ border-color: #859900;
+}
+
+.ground {
+ background-color: #002b3633;
+ border-color: #002b36;
+}
+
+.power {
+ background-color: #dc322f33;
+ border-color: #dc322f;
+}
+
+.adc {
+ background-color: #2aa19833;
+ border-color: #2aa198;
+}
+
+.system {
+ background-color: #df8f8e33;
+ border-color: #df8f8e;
+}
+
+.i2c {
+ background-color: #268bd233;
+ border-color: #268bd2;
+}
+
+.spi {
+ background-color: #d3368233;
+ border-color: #d33682;
+}
+
+.uart {
+ background-color: #6c71c433;
+ border-color: #6c71c4;
+}
+
+.pwm {
+ background-color: #33333333;
+ border-color: #333;
+}
+
+.labels.left td {
+ border-width: 0 0 0 4px;
+}
+
+.labels.right td {
+ border-width: 0 4px 0 0;
+}
+
+.labels tr:hover:before {
+ background-color: #eee;
+}
+
+.labels tr:hover .gpio {
+ background-color: #9fb80366;
+}
+
+.labels tr:hover .ground {
+ background-color: #01435366;
+}
+
+.labels tr:hover .power {
+ background-color: #f13a3766;
+}
+
+.labels tr:hover .adc {
+ background-color: #39d1c466;
+}
+
+.labels tr:hover .system {
+ background-color: #fab4b266;
+}
+
+.labels tr:hover .i2c {
+ background-color: #3ba6f166;
+}
+
+.labels tr:hover .spi {
+ background-color: #f34f9f66;
+}
+
+.labels tr:hover .uart {
+ background-color: #8d91e666;
+}
+
+.labels tr:hover .pwm {
+ background-color: #44444466;
+}
+
+.filter {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+.filter li {
+ display: inline;
+}
+
+.filter label {
+ display: inline-block;
+ color: #002b36;
+ padding: 0 10px;
+ line-height: 30px;
+ user-select: none;
+ margin-bottom: 5px;
+}
+
+.interfaces label {
+ border-width: 0 0 0 30px;
+ border-style: solid;
+}
+
+.filter input {
+ margin: 0 10px 0 0;
+}
+
+.filter.interfaces label {
+ color: #222;
+}
+
+.filter.interfaces {
+ margin-bottom: 20px;
+}
+
+.nojs ul {
+ display: none;
+}
+
+.underside {
+ display: none;
+}
+
+.underside-view .pico {
+ display: none;
+}
+
+.underside-view .underside {
+ display: block;
+}
+
+.underside-view {
+ direction: rtl;
+}
+
+.underside-view .labels.left {
+ direction: ltr;
+}
+
+@media (prefers-color-scheme: dark) {
+ body {
+ background-color: #000;
+ }
+
+ header {
+ background: #111;
+ color: #666;
+ border-bottom-color: #222;
+ }
+
+ .filter label,
+ footer p,
+ nav p {
+ color: #666;
+ }
+
+ footer a,
+ footer a:visited {
+ color: #1d6ca5;
+ }
+
+ footer a:hover {
+ color: #3ba6f1;
+ }
+
+ .labels tbody tr:before {
+ background-color: #002b36;
+ color: #e9e5d2;
+ }
+
+ .labels tbody tr:hover:before {
+ background-color: #013441;
+ }
+
+ td,
+ th,
+ .filter.interfaces label {
+ color: #e9e5d2;
+ }
+}
\ No newline at end of file
diff --git a/SD/pinout/pinout.html b/SD/pinout/pinout.html
new file mode 100644
index 0000000..05f4d13
--- /dev/null
+++ b/SD/pinout/pinout.html
@@ -0,0 +1,363 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pin |
+ Name |
+ SPI |
+ I2C |
+ UART |
+ PWM |
+
+
+ 1 |
+ GP0 |
+ SPI0 RX |
+ I2C0 SDA |
+ UART0 TX |
+ PWM0 A |
+
+ 2 |
+ GP1 |
+ SPI0 CSn |
+ I2C0 SCL |
+ UART0 RX |
+ PWM0 B |
+
+ 3 |
+ Ground |
+
+ 4 |
+ GP2 |
+ SPI0 SCK |
+ I2C1 SDA |
+ UART0 CTS |
+ PWM1 A |
+
+ 5 |
+ GP3 |
+ SPI0 TX |
+ I2C1 SCL |
+ UART0 RTS |
+ PWM1 B |
+
+ 6 |
+ GP4 |
+ SPI0 RX |
+ I2C0 SDA |
+ UART1 TX |
+ PWM2 A |
+
+ 7 |
+ GP5 |
+ SPI0 CSn |
+ I2C0 SCL |
+ UART1 RX |
+ PWM2 B |
+
+ 8 |
+ Ground |
+
+ 9 |
+ GP6 |
+ SPI0 SCK |
+ I2C1 SDA |
+ UART1 CTS |
+ PWM3 A |
+
+ 10 |
+ GP7 |
+ SPI0 TX |
+ I2C1 SCL |
+ UART1 RTS |
+ PWM3 B |
+
+ 11 |
+ GP8 |
+ SPI1 RX |
+ I2C0 SDA |
+ UART1 TX |
+ PWM4 A |
+
+ 12 |
+ GP9 |
+ SPI1 CSn |
+ I2C0 SCL |
+ UART1 RX |
+ PWM4 B |
+
+ 13 |
+ Ground |
+
+ 14 |
+ GP10 |
+ SPI1 SCK |
+ I2C1 SDA |
+ UART1 CTS |
+ PWM5 A |
+
+ 15 |
+ GP11 |
+ SPI1 TX |
+ I2C1 SCL |
+ UART1 RTS |
+ PWM5 B |
+
+ 16 |
+ GP12 |
+ SPI1 RX |
+ I2C0 SDA |
+ UART0 TX |
+ PWM6 A |
+
+ 17 |
+ GP13 |
+ SPI1 CSn |
+ I2C0 SCL |
+ UART0 RX |
+ PWM6 B |
+
+ 18 |
+ Ground |
+
+ 19 |
+ GP14 |
+ SPI1 SCK |
+ I2C1 SDA |
+ UART0 CTS |
+ PWM7 A |
+
+ 20 |
+ GP15 |
+ SPI1 TX |
+ I2C1 SCL |
+ UART0 RTS |
+ PWM7 B |
+
+
+
+
+
+
+
+
+
+
+
+ Pin |
+ Name/ADC |
+ SPI |
+ I2C |
+ UART |
+ PWM |
+
+
+
+ 40 |
+ VBUS |
+
+
+ 39 |
+ VSYS |
+
+
+ 38 |
+ Ground |
+
+
+ 37 |
+ 3V3 En |
+
+
+ 36 |
+ 3V3 Out |
+
+ 35 |
+ ADC VRef |
+
+ 34 |
+ GP28 / A2 |
+ SPI1 RX |
+ I2C0 SDA |
+ UART0 TX |
+ PWM6 A |
+
+ 33 |
+ ADC Gnd |
+
+ 32 |
+ GP27 / A1 |
+ SPI1 TX |
+ I2C1 SCL |
+ UART1 RTS |
+ PWM5 B |
+
+ 31 |
+ GP26 / A0 |
+ SPI1 SCK |
+ I2C1 SDA |
+ UART1 CTS |
+ PWM5 A |
+
+ 30 |
+ RUN |
+
+ 29 |
+ GP22 |
+ SPI0 SCK |
+ I2C1 SDA |
+ UART1 CTS |
+ PWM3 A |
+
+ 28 |
+ Ground |
+
+ 27 |
+ GP21 |
+ SPI0 CSn |
+ I2C0 SCL |
+ UART1 RX |
+ PWM2 B |
+
+ 26 |
+ GP20 |
+ SPI0 RX |
+ I2C0 SDA |
+ UART1 TX |
+ PWM2 A |
+
+ 25 |
+ GP19 |
+ SPI0 TX |
+ I2C1 SCL |
+ UART0 RTS |
+ PWM1 B |
+
+
+ 24 |
+ GP18 |
+ SPI0 SCK |
+ I2C1 SDA |
+ UART0 CTS |
+ PWM1 A |
+
+
+ 23 |
+ Ground |
+
+
+ 22 |
+ GP17 |
+ SPI0 CSn |
+ I2C0 SCL |
+ UART0 RX |
+ PWM0 B |
+
+
+ 21 |
+ GP16 |
+ SPI0 RX |
+ I2C0 SDA |
+ UART0 TX |
+ PWM0 A |
+
+
+
+
+
+
+
+
+
+
diff --git a/SD/pinout/pinout.js b/SD/pinout/pinout.js
new file mode 100644
index 0000000..e8bc824
--- /dev/null
+++ b/SD/pinout/pinout.js
@@ -0,0 +1,41 @@
+'use strict';
+var pinout=document.getElementById("pinout");
+var inputs=document.getElementsByTagName("input");
+var advanced=document.querySelectorAll(".advanced");
+document.getElementById("nav").classList.remove("nojs");
+for(var i=0;i
+
\ No newline at end of file
diff --git a/SD/pinout/raspberry-pi-pico.svg b/SD/pinout/raspberry-pi-pico.svg
new file mode 100644
index 0000000..f00928a
--- /dev/null
+++ b/SD/pinout/raspberry-pi-pico.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/SD/pinout/register_serviceworker.js b/SD/pinout/register_serviceworker.js
new file mode 100644
index 0000000..6568fd2
--- /dev/null
+++ b/SD/pinout/register_serviceworker.js
@@ -0,0 +1,8 @@
+if('serviceWorker'in navigator){
+ let registration;
+ const registerServiceWorker = async() => {
+ registration = await navigator.serviceWorker.register('sw.js');
+ console.log(`Service Worker Registration (Scope: ${registration.scope})`);
+ };
+ registerServiceWorker();
+}
\ No newline at end of file
diff --git a/SD/settings/settings.html b/SD/settings/settings.html
new file mode 100644
index 0000000..890a810
--- /dev/null
+++ b/SD/settings/settings.html
@@ -0,0 +1,153 @@
+
+
+
+
+ Pico Index
+
+
+
+ PicoW settings page
+
+ Main page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test:
+ Device name:
+ ADC resolution:
+ Axis resolution:
+ Axis count:
+ Button count:
+ Hat count:
+
+
+
+
diff --git a/SD/settings/settings.js b/SD/settings/settings.js
new file mode 100644
index 0000000..61629c7
--- /dev/null
+++ b/SD/settings/settings.js
@@ -0,0 +1,204 @@
+var hexCol = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"]
+var hexRow = ["00:","10:","20:","30:","40:","50:","60:","70:","80:","90:","A0:","B0:","C0:","D0:","E0:","F0:"]
+var usagePageList = {
+ "Undefined": 0x00,
+ "Generic Desktop Controls": 0x01,
+ "Simulation Controls": 0x02,
+ "VR Controls": 0x03,
+ "Sport Controls": 0x04,
+ "Game Controls": 0x05,
+}
+var usagePageSubList = {
+ "Undefined": {
+ "Undefined":0x00
+ },
+ "Generic Desktop Controls": {
+ "Undefined": 0x00,
+ "Pointer": 0x01,
+ "Mouse": 0x02,
+ "Joystick": 0x04,
+ "Game Pad": 0x05,
+ "keyboard": 0x06,
+ "Multi-axis COntroller": 0x08
+ },
+ "Simulation Controls": {
+ "Undefined" : 0x00,
+ "Flight Simulation Device": 0x01,
+ "Automobile Simulation Device": 0x02,
+ "Tank Simulation Device": 0x03,
+ "Spaceship Simulation Device": 0x04,
+ "Submarine Simulation Device": 0x05, // OceanGate anyone?
+ "Sailing Simulation Device": 0x06,
+ "Motorcycle Simulation Device": 0x07,
+ "Sports Simulation Device": 0x08,
+ "Airplane Simulation Device": 0x09,
+ "Helicopter Simulation Device": 0x0A,
+ "Magic Carpet Simulation Device": 0x0B,
+ "Bicycle Simulation Device": 0x0C
+ }
+}
+
+// test
+
+var usagePage = 0;
+var usage = 0;
+var axisCount=0;
+var ButtonCount=0;
+var HatCount=0;
+
+function onBodyLoad() {
+ console.log("we are loaded!!");
+ setTimeout(getI2CList, 500);
+ getHIDValues();
+ onListSelect();
+ populateUsagePage();
+ //document.getElementById("devicename").addEventListener("change", );
+ //document.getElementById("axiscount").addEventListener("change", updateAxis);
+ //document.getElementById("hatcount").addEventListener("change", updateHats);
+ //document.getElementById("buttoncount").addEventListener("change", updateButtons);
+ document.getElementById("UsagePageType").addEventListener("change", UsagePageTypeChanged);
+ document.getElementById("UsagePageSubType").addEventListener("change", UsagePageSubTypeChanged);
+}
+
+function onListSelect() {
+ var mylist = document.getElementById("myList");
+ document.getElementById("favourite").value = mylist.options[mylist.selectedIndex].text;
+}
+
+async function getI2CList() {
+ const res = await fetch("listI2C?");
+ var ids = await res.json();
+ var tbodyRef = document.getElementById('I2CTable').getElementsByTagName('tbody')[0];
+ // Clear the existing data
+ tbodyRef.innerHTML = '';
+ // Insert a row at the end of table
+ var newRow = tbodyRef.insertRow();
+ var newCell = newRow.insertCell();
+ var newText = document.createTextNode("");
+ newCell.appendChild(newText);
+ var row = 0;
+ for (var i = 0; i<16; i++) {
+ var newCell = newRow.insertCell();
+ var newText = document.createTextNode(hexCol[i]);
+ newCell.appendChild(newText);
+ }
+ var newRow = tbodyRef.insertRow();
+ var row = 0;
+ for (var j = 0; j<128; j++) {
+ if ((j % 16) == 0) {
+ var newCell = newRow.insertCell();
+ var newText = document.createTextNode(hexRow[row]);
+ newCell.appendChild(newText);
+ }
+ var newCell = newRow.insertCell();
+ if (ids.includes(j) == true) {
+ if (j<7)
+ var newText = document.createTextNode('!');
+ else
+ var newText = document.createTextNode('X');
+ } else {
+ if (j<7)
+ var newText = document.createTextNode(' ');
+ else
+ var newText = document.createTextNode('-');
+ }
+ newCell.appendChild(newText);
+ // Insert a row at the end of table when we have 16 items
+ if ( (j+1)%16 == 0) {
+ var newRow = tbodyRef.insertRow();
+ row++;
+ }
+ }
+ setTimeout(getI2CList, 500);
+}
+
+function updateAxis() {
+// fetch("settings/updatehid?axis="+ document.getElementById("axiscount").value);
+}
+
+function updateButtons() {
+// fetch("settings/updatehid?buttons="+ document.getElementById("buttoncount").value);
+}
+
+function updateHats() {
+// fetch("settings/updatehid?hats="+ document.getElementById("hatcount").value);
+}
+
+async function getHIDValues() {
+ //const current_state = await fetch("settings/updatehid?getValues=");
+ //var values = await current_state.json();
+ var response;
+
+ response = await fetch("settings/updatehid?usagepage=");
+ //document.getElementById("axiscount").value = response.text();
+ response = await fetch("settings/updatehid?usage=");
+ //document.getElementById("axiscount").value = response.text();
+ response = await fetch("settings/updatehid?devicename=");
+ document.getElementById("devicename").value = await response.text();
+ response = await fetch("settings/updatehid?adcresolution=");
+ document.getElementById("adcresolution").value = await response.text();
+ response = await fetch("settings/updatehid?axisresolution=");
+ document.getElementById("axisresolution").value = await response.text();
+ response = await fetch("settings/updatehid?axis=");
+ document.getElementById("axiscount").value = await response.text(); // values[0];
+ response = await fetch("settings/updatehid?buttons=");
+ document.getElementById("buttoncount").value = await response.text(); //values[1];
+ response = await fetch("settings/updatehid?hats=");
+ document.getElementById("hatcount").value = await response.text(); //values[2];
+}
+
+function updateHID() {
+ fetch("settings/updatehid?"+
+ "devicename="+document.getElementById("devicename").value+
+ "&axisresolution="+document.getElementById("axisresolution").value+
+ "&adcresolution="+document.getElementById("adcresolution").value+
+ "&usagepage="+ usagePage+
+ "&usage="+ usage+
+ "&axis="+ document.getElementById("axiscount").value+
+ "&buttons="+ document.getElementById("buttoncount").value+
+ "&hats="+ document.getElementById("hatcount").value+
+ "&restart="
+ );
+ //await fetch("settings/updatehid?usagepage="+ usagePage);
+ //await fetch("settings/updatehid?usage="+ usage);
+ //await fetch("settings/updatehid?axis="+ document.getElementById("axiscount").value);
+ //await fetch("settings/updatehid?hats="+ document.getElementById("hatcount").value);
+ //await fetch("settings/updatehid?buttons="+ document.getElementById("buttoncount").value);
+ //await fetch("settings/updatehid?restart=");
+}
+
+function populateUsagePage() {
+ var usageListPageType = document.getElementById("UsagePageType");
+ usageListPageType.innerHTML = '';
+ console.log(usagePageList);
+
+ for (const [k,v] of Object.entries(usagePageList)) {
+ console.log(k + "-" + v);
+ usageListPageType.add( new Option(k, v));
+ }
+}
+
+function UsagePageTypeChanged(e) {
+ var index = e.target.options.selectedIndex;
+ console.log(index);
+ usagePage = index;
+ var key = e.target.options[index].innerText;
+ console.log(key);
+ var sublist = usagePageSubList[key];
+ console.log(sublist);
+ var UsagePageSubType = document.getElementById("UsagePageSubType");
+ UsagePageSubType.innerHTML = '';
+ if (sublist) {
+ for (const [k,v] of Object.entries(sublist)) {
+ UsagePageSubType.add( new Option(k, v));
+ }
+ } else {
+ UsagePageSubType.add( new Option("unsupported"));
+ }
+}
+
+function UsagePageSubTypeChanged(e) {
+ console.log(e.target.options[e.target.options.selectedIndex].label);
+ usage = e.target.options[e.target.options.selectedIndex].value;
+ console.log(usagePage, usage);
+}
diff --git a/config/common.ini b/config/common.ini
index d760608..d355082 100644
--- a/config/common.ini
+++ b/config/common.ini
@@ -4,7 +4,7 @@ platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = rpipico
board_build.core = earlephilhower
framework = arduino
-board_build.flash_mode = qio
+;board_build.flash_mode = qio
;monitor_filters = default, colorize
;monitor_speed = 115200
debug_speed = 10000
@@ -49,35 +49,34 @@ debug_init_break = tbreak setup
board_build.f_cpu = 250000000L ;250Mhz (OC)
;board_build.f_cpu = 270000000L ;270Mhz (OC) (custom) (RAM ONLY)
-build_flags =
-
[pico_common]
platform_packages =
- ;https://github.com/raspberrypi/openocd.git@^2.12.0
- ;platformio/tool-openocd-raspberrypi@^2.1000.0
+ ;toolchain-rp2040-earlephilhower
build_flags =
;-fstack-usage
- -Waddress
- -Wcomment
- -Wformat
- -Wbool-compare
- -Wuninitialized
- -Wunknown-pragmas
- -Wunused-value
- -Wimplicit-fallthrough
- -Wunused
- -Wpointer-arith
- -Wno-missing-braces
- -O3
- -fno-exceptions
- -D PIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
+; -Waddress
+; -Wcomment
+; -Wformat
+; -Wbool-compare
+; -Wuninitialized
+; -Wunknown-pragmas
+; -Wunused-value
+; -Wimplicit-fallthrough
+; -Wunused
+; -Wpointer-arith
+; -Wno-missing-braces
+; -fno-exceptions
+ -Os
+; -D PIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
-D I2CSPEED=100000
libs =
;https://github.com/IWILZ/PicoSem.git
robtillaart/CRC @ ^1.0.2
Adafruit NeoPixel @ ^1.12.0
+ ;olikraus/U8g2 @ ^2.35.19
+ ;U8g2
diff --git a/config/i2c_node.ini b/config/i2c_node.ini
index 170d0a8..63bf723 100644
--- a/config/i2c_node.ini
+++ b/config/i2c_node.ini
@@ -15,8 +15,6 @@ build_flags =
lib_deps =
${pico_common.libs}
+
debug_build_flags =
- ;-O0
- ;-Og
- ;-g3
-ggdb
\ No newline at end of file
diff --git a/config/usb.ini b/config/usb.ini
index 8e6b35a..fceea28 100644
--- a/config/usb.ini
+++ b/config/usb.ini
@@ -25,17 +25,16 @@ build_flags =
-D CFG_TUH_MSC=0
-D CFG_TUD_VIDEO=0
-D CFG_TUD_VENDOR=0
- -D CFG_TUD_MSC=0
+ -D CFG_TUD_MSC=1
-D CFG_TUD_MIDI=0
lib_deps =
${pico_common.libs}
Adafruit TinyUSB Library @ ^3.0.0
-extra_scripts = pre:patch-SDFS.py
+extra_scripts =
+ pre:scripts/patch-SDFS.py
+ ;pre:scripts/picoasm.py
debug_build_flags =
- ;-O0
- ;-Og
- ;-g3
-ggdb
diff --git a/desktop-descriptor.c b/desktop-descriptor.c
index caf45cb..fcd0e7b 100644
--- a/desktop-descriptor.c
+++ b/desktop-descriptor.c
@@ -1,5 +1,6 @@
#define DESKTOP_ONLY
#include
+#include
#include
#include
#include
@@ -18,18 +19,23 @@ typedef struct {
uint8_t axis;
} input_id;
+
+bool enableKeyboard = 1;
+bool enableMouse = 1;
+bool enableMsc = 0;
+uint8_t IdCount;
+uint8_t MaxDeviceCount = MAX_REPORT_ID;
+
+
uint8_t device_max_button_count = 79;
uint8_t device_max_hat_count = 4;
uint8_t device_max_axis_count = 9;
uint32_t AxisResolution = 11;
uint16_t AxisCount = 8;
-uint16_t ButtonCount = 65;
+uint16_t ButtonCount = 64;
uint16_t HatCount = 1;
-uint8_t hid_usage_page_val = HID_USAGE_PAGE_DESKTOP;
-uint8_t hid_usage_val = HID_USAGE_DESKTOP_JOYSTICK;
-uint8_t DeviceCount=0;
uint usb_report_size;
uint8_t usb_report[MAX_HID_DESCRIPTOR_SIZE];
@@ -39,8 +45,6 @@ uint16_t button_start[MAX_REPORT_ID];
uint16_t hat_start[MAX_REPORT_ID];
uint16_t total_bits[MAX_REPORT_ID];
uint8_t reports[MAX_REPORT_ID][64];
-uint8_t old_reports[MAX_REPORT_ID][64];
-uint8_t readyToUpdate[MAX_REPORT_ID];
uint16_t largest_bits;
@@ -88,7 +92,29 @@ void set_hat(uint8_t *report, uint8_t reportid, uint8_t hat, uint8_t value) {
}
}
-void setupUSB() {
+void setupDescripor() {
+ uint16_t maxBuffSize = MAX_HID_DESCRIPTOR_SIZE;
+ if (enableMouse)
+ maxBuffSize -= 79;
+// MaxDeviceCount -= 1;
+ if (enableKeyboard)
+ maxBuffSize -= 67;
+// MaxDeviceCount -= 1;
+
+ // reset the connection
+ memset(inputs_id, 0, sizeof(inputs_id));
+ memset(usb_report, 0, sizeof(usb_report));
+ memset(button_start,0,sizeof(button_start));
+ memset(hat_start,0,sizeof(hat_start));
+ memset(axis_start,0,sizeof(axis_start));
+ memset(total_bits,0,sizeof(total_bits));
+ usb_report_size=0;
+ IdCount=0;
+
+ //this buffer will be cleared and freed at the end since its a temp buffer
+ uint8_t* t_buffer = (uint8_t*)malloc(150);
+ memset(t_buffer,0,150);
+ uint t_buffer_size;
/*
Calculate how many "devices" we will need to emulate
@@ -96,33 +122,48 @@ void setupUSB() {
Calculate how many hats per "device"
Calculate how many axis per "device"
*/
- memset(inputs_id, 0, sizeof(inputs_id));
- memset(usb_report, 0, sizeof(usb_report));
- memset(button_start,0, sizeof(button_start));
- memset(hat_start,0, sizeof(hat_start));
- memset(axis_start,0, sizeof(axis_start));
- usb_report_size=0;
- largest_bits=0;
- DeviceCount=0;
-
+
for (uint16_t i=ButtonCount, j=1; i>0; i-=MIN(device_max_button_count,i), j++) {
inputs_id[j].buttons = i>device_max_button_count ? device_max_button_count:i;
- DeviceCount = j>DeviceCount ? j:DeviceCount;
+ IdCount = j>IdCount ? j:IdCount;
}
for (uint16_t i=HatCount, j=1; i>0; i-=MIN(device_max_hat_count, i), j++) {
inputs_id[j].hats = i>device_max_hat_count ? device_max_hat_count:i;
- DeviceCount = j>DeviceCount ? j:DeviceCount;
+ IdCount = j>IdCount ? j:IdCount;
}
for (uint8_t i=AxisCount, j=1; i>0;i-=MIN(device_max_axis_count,i), j++) {
inputs_id[j].axis = i>device_max_axis_count ? device_max_axis_count:i;
- DeviceCount = j>DeviceCount ? j:DeviceCount;
+ IdCount = j>IdCount ? j:IdCount;
+ }
+ for (uint16_t id = 1; id<=IdCount; id++) {
+ t_buffer_size = 0;
+ makeJoystickDescriptor(id, AxisResolution, inputs_id[id].axis, inputs_id[id].hats, inputs_id[id].buttons, t_buffer, &t_buffer_size);
+ if (usb_report_size + t_buffer_size < maxBuffSize) {
+ memmove(usb_report+usb_report_size, t_buffer, t_buffer_size);
+ usb_report_size += t_buffer_size;
+ }
+ memset(t_buffer, 0, 150);
+// makeJoystickDescriptor(id, AxisResolution, inputs_id[id].axis, inputs_id[id].hats, inputs_id[id].buttons, usb_report, &usb_report_size);
}
- for (uint16_t i = 1; i<=DeviceCount; i++) {
- makeDescriptor(i, AxisResolution, inputs_id[i].axis, inputs_id[i].hats, inputs_id[i].buttons, usb_report, &usb_report_size);
+ if (enableKeyboard) {
+ t_buffer_size = 0;
+ makeKeyboardDescriptor(IdCount+1,t_buffer, &t_buffer_size);
+ if (usb_report_size + t_buffer_size < MAX_HID_DESCRIPTOR_SIZE) {
+ memmove(usb_report+usb_report_size,t_buffer,t_buffer_size);
+ usb_report_size += t_buffer_size;
+ memset(t_buffer,0,150);
+ }
}
- for (uint8_t rep = 1; rep < MAX_REPORT_ID; rep++) {
- largest_bits = (largest_bits < total_bits[rep]) ? total_bits[rep] : largest_bits;
+ if (enableMouse) {
+ t_buffer_size = 0;
+ makeMouseDescriptor(IdCount+2,t_buffer, &t_buffer_size);
+ if (usb_report_size + t_buffer_size < MAX_HID_DESCRIPTOR_SIZE) {
+ memmove(usb_report+usb_report_size,t_buffer,t_buffer_size);
+ usb_report_size += t_buffer_size;
+ memset(t_buffer,0,150);
+ }
}
+ free(t_buffer);
}
int main(int argc, char **argv) {
@@ -134,9 +175,8 @@ int main(int argc, char **argv) {
HatCount,
ButtonCount
);
- setupUSB();
- AxisCount = 0;
- setupUSB();
+ setupDescripor();
+
for (uint8_t i = 0; i <8; i++) {
set_axis(reports[1],1,i,(1<
#include
#include
-enum command {
- SetConfig = 0B0000000000000010,
- GetConfig = 0B0000000000000011,
- SetLed = 0B0000000000000100,
- GetLed = 0B0000000000000101,
- SetAxis = 0B0000000000001000,
- GetAxis = 0B0000000000001001,
- SetButton = 0B0000000000010000,
- GetButton = 0B0000000000010001,
- //Set = 0B0000000000100000,
- //Get = 0B0000000000100001,
- //Set = 0B0000000001000000,
- //Get = 0B0000000001000001,
- //Set = 0B0000000010000000,
- //Get = 0B0000000010000001,
-
- //Set = 0B0000000100000000,
- //Get = 0B0000000100000001,
- //Set = 0B0000001000000000,
- //Get = 0B0000001000000001,
- //Set = 0B0000010000000000,
- //Get = 0B0000010000000001,
- //Set = 0B0000100000000000,
- //Get = 0B0000100000000001,
- //Set = 0B0001000000000000,
- //Get = 0B0001000000000001,
- //Set = 0B0010000000000000,
- //Get = 0B0010000000000001,
- //Set = 0B0100000000000000,
- //Get = 0B0100000000000001,
- //Set = 0B1000000000000000,
- //Get = 0B1000000000000001,
-// ||||||||||||||||
-// /|||||||||||||||
-// /||||||||||||||
-// /|||||||||||||
-// /||||||||||||
-// /|||||||||||
-// /||||||||||
-// /|||||||||
-// /||||||||
-// /|||||||
-// /||||||
-// /|||||
-// BUTTON BIT --------------/||||
-// AXIS BIT------------------/|||
-// LED BIT -------------------/||
-// CONFIG BIT -----------------/|
-// SET/GET BIT -----------------/
- UpdateFirmware = 0B1111111111111111 // ONLY USED FOR MODIFYING THE FIRMWARE
-};
-enum ConfigCommands {
- AnalogResolution = 0B00000001,
- GetAnalog = 0B00000010
-};
-
-enum AxisInputs {
- X,
- Y,
- Z,
- Rx,
- Ry,
- Rz,
- S,
- D,
- W,
+enum commandType {
+ Config = 0B00000010,
+ //Config = 0B00000011,
+ SetLed = 0B00000100,
+ GetLed = 0B00000101,
+ SetAxis = 0B00001000,
+ GetAxis = 0B00001001,
+ SetButton = 0B00010000,
+ GetButton = 0B00010001,
+ SetMuxId = 0B00100000,
+ GetMuxId = 0B00100001,
+ //Set = 0B01000000,
+ //Get = 0B01000001,
+ //Set = 0B10000000,
+ //Get = 0B10000001,
};
-enum Buttons {
- Button1 = 1,
- Button2 ,
- Button3 ,
- Button4 ,
- Button5 ,
- Button6 ,
- Button7 ,
- Button8 ,
- Button9 ,
- Button10 ,
- Button11 ,
- Button12 ,
- Button13 ,
- Button14 ,
- Button15 ,
- Button16 ,
- Button17 ,
- Button18 ,
- Button19 ,
- Button20 ,
- Button21 ,
- Button22 ,
- Button23 ,
- Button24 ,
- Button25 ,
- Button26 ,
-
+enum ConfigCommands {
+ SetI2cId = 0B0000000000000010,
+ GetI2cId = 0B0000000000000011,
+ SetChipId = 0B0000000000000100,// meant for testing only
+ GetChipId = 0B0000000000000101,
+ SetWS2812LedPin = 0B0000000000001000,
+ GetWS2812LedPin = 0B0000000000001001,
+ SetAnalogResolution = 0B0000000000010000,
+ GetAnalogResolution = 0B0000000000010001,
+ SetButtonPin = 0B0000000000100000,
+ GetButtonPin = 0B0000000000100001,
+ SetAxisPin = 0B0000000001000000,
+ GetAxisPin = 0B0000000001000001,
+ SetHatPins = 0B0000000010000000,
+ GetHatPins = 0B0000000010000001,
+ SetMuxPins = 0B0000000100000000,
+ GetMuxPins = 0B0000000100000001,
+ SetButtonCount = 0B0000001000000000,
+ GetButtonCount = 0B0000001000000001,
+ SetHatCount = 0B0000010000000000,
+ GetHatCount = 0B0000010000000001,
+ SetAxisCount = 0B0000100000000000,
+ GetAxisCount = 0B0000100000000001,
+ SetMuxCount = 0B0001000000000000,
+ GetMuxCount = 0B0001000000000001,
+ SetDigitalPinMode = 0B0010000000000000,
+ GetDigitalPinMode = 0B0010000000000001,
+ SetAnalogPinMode = 0B0100000000000000,
+ GetAnalogPinMode = 0B0100000000000001,
+ SetInvert = 0B1000000000000000,
+ GetInvert = 0B1000000000000001,
+ // ONLY USED FOR MODIFYING THE FIRMWARE SETTINGS
+ // WILL FORCE A REBOOT AFTERWARDS
+ ConfigUpdate = 0B1111111111111111
};
-
-struct __attribute__((packed, aligned(1))) Input_Config {
- uint8_t input_type;
- uint8_t input_id;
- char input_name;
-};
diff --git a/include/HID_Report.h b/include/HID_Report.h
deleted file mode 100755
index 5b64bd2..0000000
--- a/include/HID_Report.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/// HID Gamepad Protocol Report.
-
-
-typedef struct TU_ATTR_PACKED
-{
- uint64_t buttons ; ///< Buttons mask for currently pressed buttons
- uint8_t hat1 :4 ; ///< Buttons mask for currently pressed buttons in the DPad/hat
- uint8_t hat2 :4 ; ///< Buttons mask for currently pressed buttons in the DPad/hat
- int16_t x ; ///< Delta x movement of left analog-stick
- int16_t y ; ///< Delta y movement of left analog-stick
- int16_t z ; ///< Delta z movement of analog right trigger
- int16_t rx ; ///< Delta Rz movement of right analog-joystick
- int16_t ry ; ///< Delta Rx movement of analog left trigger
- int16_t rz ; ///< Delta Rz movement of right analog-joystick
- int16_t slider ; ///< Delta Ry movement of analog right trigger
- int16_t dial ; ///< Delta Ry movement of analog right trigger
-
-
-}hid_Joystick_report_t;
-
-
diff --git a/include/HID_descriptor.h b/include/HID_descriptor.h
index c6087b6..b402d01 100755
--- a/include/HID_descriptor.h
+++ b/include/HID_descriptor.h
@@ -1,6 +1,6 @@
#include "hid.h"
-void makeDescriptor(uint8_t reportID, uint8_t bitsPerAxis, uint8_t axisCount,uint8_t hatCount, uint8_t buttonCount, uint8_t *buffer, uint *bufferSize) {
+void makeJoystickDescriptor(uint8_t reportID, uint8_t bitsPerAxis, uint8_t axisCount,uint8_t hatCount, uint8_t buttonCount, uint8_t *buffer, uint *bufferSize) {
extern uint16_t axis_start[];
extern uint16_t hat_start[];
extern uint16_t button_start[];
@@ -90,9 +90,117 @@ void makeDescriptor(uint8_t reportID, uint8_t bitsPerAxis, uint8_t axisCount,uin
*bufferSize = p - buffer;
}
-uint8_t *_makeDescriptor(uint8_t reportID, uint8_t bitsPerAxis, uint8_t axisCount,uint8_t hatCount, uint8_t buttonCount,uint *bufferSize) {
+uint8_t *_makeJoystickDescriptor(uint8_t reportID, uint8_t bitsPerAxis, uint8_t axisCount,uint8_t hatCount, uint8_t buttonCount,uint *bufferSize) {
uint8_t *buffer = (uint8_t*)malloc(MAX_HID_DESCRIPTOR_SIZE);
*bufferSize = 0;
- makeDescriptor(reportID, bitsPerAxis, axisCount, hatCount, buttonCount, buffer, bufferSize);
+ makeJoystickDescriptor(reportID, bitsPerAxis, axisCount, hatCount, buttonCount, buffer, bufferSize);
return buffer;
-}
\ No newline at end of file
+}
+void makeKeyboardDescriptor(uint8_t reportID, uint8_t *buffer, uint *bufferSize) {
+ extern uint16_t total_bits[];
+ uint8_t *p = buffer+*bufferSize;
+ sp=0;
+ bits=0;
+
+ hid_usage_page(&p, HID_USAGE_PAGE_DESKTOP);
+ hid_usage(&p, HID_USAGE_DESKTOP_KEYBOARD);
+ hid_collection(&p, HID_COLLECTION_APPLICATION);
+
+ hid_report_id(&p, reportID);
+
+ hid_usage_page(&p, HID_USAGE_PAGE_KEYBOARD);
+ hid_usage_min(&p, 224);
+ hid_usage_max(&p, 231);
+ hid_logical_min(&p, 0);
+ hid_logical_max(&p, 1);
+ hid_report_count(&p, 8);
+ hid_report_size(&p, 1);
+ hid_input(&p, HID_DATA | HID_VARIABLE | HID_ABSOLUTE);
+
+ hid_report_count(&p, 1);
+ hid_report_size(&p, 8);
+ hid_input(&p, HID_CONSTANT);
+
+ hid_usage_page(&p, HID_USAGE_PAGE_LED);
+ hid_usage_min(&p, 1);
+ hid_usage_max(&p, 5);
+ hid_report_count(&p, 5);
+ hid_report_size(&p, 1);
+ hid_input(&p, HID_DATA | HID_VARIABLE | HID_ABSOLUTE);
+
+ hid_report_count(&p, 1);
+ hid_report_size(&p, 3);
+ hid_input(&p, HID_CONSTANT);
+
+ hid_usage_page(&p, HID_USAGE_PAGE_KEYBOARD);
+ hid_usage_min(&p, 0);
+ hid_usage_max(&p, 255);// ,2);
+ hid_logical_min(&p, 0);
+ hid_logical_max(&p, 255);//,2);
+ hid_report_count(&p, 6);
+ hid_report_size(&p, 8);
+ hid_input(&p, HID_DATA | HID_ARRAY | HID_ABSOLUTE);
+ hid_collection_end(&p);
+
+ total_bits[reportID] = bits;
+ *bufferSize = p - buffer;
+
+}
+void makeMouseDescriptor(uint8_t reportID, uint8_t *buffer, uint *bufferSize) {
+ extern uint16_t total_bits[];
+ uint8_t *p = buffer+*bufferSize;
+ sp=0;
+ bits=0;
+
+ hid_usage_page(&p, HID_USAGE_PAGE_DESKTOP);
+ hid_usage(&p, HID_USAGE_DESKTOP_MOUSE);
+ hid_collection(&p, HID_COLLECTION_APPLICATION);
+
+ hid_report_id(&p, reportID);
+
+ hid_usage(&p, HID_USAGE_DESKTOP_POINTER);
+ hid_collection(&p, HID_COLLECTION_PHYSICAL);
+ hid_usage_page(&p, HID_USAGE_PAGE_BUTTON);
+ hid_usage_min(&p, 1);
+ hid_usage_max(&p, 5);
+ hid_logical_min(&p, 0);
+ hid_logical_max(&p, 1);
+ hid_report_count(&p, 5);
+ hid_report_size(&p, 1);
+ hid_input(&p, HID_DATA | HID_VARIABLE | HID_ABSOLUTE);
+
+ hid_report_count(&p, 1);
+ hid_report_size(&p, 3);
+ hid_input(&p, HID_CONSTANT);
+
+ hid_usage_page(&p, HID_USAGE_PAGE_DESKTOP);
+ hid_usage(&p, HID_USAGE_DESKTOP_X);
+ hid_usage(&p, HID_USAGE_DESKTOP_Y);
+ hid_usage_min(&p, 129);
+ hid_usage_max(&p, 127);
+ hid_report_count(&p, 2);
+ hid_report_size(&p, 8);
+ hid_input(&p, HID_DATA | HID_VARIABLE | HID_RELATIVE);
+
+ hid_usage(&p, HID_USAGE_DESKTOP_WHEEL);
+ hid_usage_min(&p, 129);
+ hid_usage_max(&p, 127);
+ hid_report_count(&p, 1);
+ hid_report_size(&p, 8);
+ hid_input(&p, HID_DATA | HID_VARIABLE | HID_RELATIVE);
+
+ hid_usage_page(&p, HID_USAGE_PAGE_CONSUMER);
+ hid_usage(&p, HID_USAGE_CONSUMER_AC_PAN);//,2);
+ hid_usage_min(&p, 129);
+ hid_usage_max(&p, 127);
+ hid_report_count(&p, 1);
+ hid_report_size(&p, 8);
+ hid_input(&p, HID_DATA | HID_VARIABLE | HID_RELATIVE);
+
+ hid_collection_end(&p);
+ hid_collection_end(&p);
+
+ total_bits[reportID] = bits;
+ *bufferSize = p - buffer;
+
+}
diff --git a/include/hid_minimal.h b/include/hid_minimal.h
index 7a17fa2..cb15989 100644
--- a/include/hid_minimal.h
+++ b/include/hid_minimal.h
@@ -188,23 +188,6 @@ enum {
HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09,
};
-//#define HID_USAGE_PAGE(x) 0x5, x
-//#define HID_USAGE(x) 0x9, x
-//#define HID_COLLECTION(x) 0xa1, x
-//#define HID_COLLECTION_END 0xc0
-//#define HID_REPORT_COUNT(x) 0x95, x
-//#define HID_REPORT_SIZE(x) 0x75, x
-//#define HID_LOGICAL_MIN(x) 0x15, x
-//#define HID_LOGICAL_MAX(x) 0x26, (x & 0xff), (x >> 8)
-//#define HID_PHYSICAL_MIN(x) 0x35, x
-//#define HID_PHYSICAL_MAX(x) 0x46, (x & 0xff), (x >> 8)
-//#define HID_INPUT(x) 0x81, x
-//#define HID_PUSH 0xa4
-//#define HID_POP 0xb4
-//#define HID_USAGE_MIN(x) 0x19, x
-//#define HID_USAGE_MAX(x) 0x29, x
-//#define HID_REPORT_ID(x) 0x85, x
-
#define HID_DATA (0<<0)
#define HID_CONSTANT (1<<0) //1
#define HID_ARRAY (0<<1)
diff --git a/include/webInterface.h b/include/webInterface.h
index e991212..99a881d 100644
--- a/include/webInterface.h
+++ b/include/webInterface.h
@@ -588,7 +588,7 @@ void updateHid() {
extern void readSystemINI();
if (server.hasArg("devicename")) {
String a = server.arg("devicename");
- if (a.length()>0) {
+ if (a.length()> 0) {
DeviceName = a;
server.send(200);
} else {
@@ -691,7 +691,8 @@ void updateHid() {
if (server.hasArg("restart")) {
server.send(200);
writeSystemINI();
- setupUSB(false);
+ setupDescripor();
+ setUSB(false);
}
}
@@ -791,7 +792,7 @@ void setupWifi() {
// Get I2C slave list
server.on("/listI2C", i2cResult);
- server.on("/settings",[](){if(handleFileRead(F("/settings.html"))) {return;}});
+ server.on("/settings",[](){if(handleFileRead(F("/settings/settings.html"))) {return;}});
server.on("/settings/updatehid",updateHid);
@@ -816,6 +817,7 @@ void setupWifi() {
server.on("/edit/index.html", [](){if (!is_authenticated()) {server.send(403);return;} handleGetEdit();});
server.on("/",[](){if(handleFileRead(F("/index.html"))) {return;}});
+ server.on("/pinout",[](){if(handleFileRead(F("/pinout/pinout.html"))) {return;}});
// Default handler for all URIs not defined above
// Use it to read files from filesystem
diff --git a/lib/X52-HOTAS/src/new_x52_common.h b/lib/X52-HOTAS/src/new_x52_common.h
new file mode 100644
index 0000000..45d9173
--- /dev/null
+++ b/lib/X52-HOTAS/src/new_x52_common.h
@@ -0,0 +1,149 @@
+#pragma once
+
+#ifndef X52_COMMON
+#define X52_COMMON
+
+#include
+#include
+
+
+// X52_DEBUG turns serial logging on/off.
+// Don't forget to turn it off in your finished "product".
+#ifndef X52_DEBUG
+ #define X52_DEBUG 0
+#endif
+
+#if X52_DEBUG
+ #ifndef X52DebugPrint
+ #define X52DebugPrint(x) Serial.print(x)
+ #endif
+ #ifndef X52DebugPrintln
+ #define X52DebugPrintln(x) {X52DebugPrint(x); X52DebugPrint("\n");}
+ #endif
+#else
+ #undef X52DebugPrint
+ #undef X52DebugPrintln
+ #define X52DebugPrint(x)
+ #define X52DebugPrintln(x)
+#endif
+
+#ifndef X52_BUSY_WAIT
+ #define X52_BUSY_WAIT 1
+#endif
+
+
+//namespace x52 {
+
+
+// Direction flag.
+// An instance of this type is a bitwise combination of zero or more enum members.
+enum Direction {
+ NoDirection = 0,
+ Right = 1,
+ Down = 2,
+ Left = 4,
+ Up = 8,
+ DownLeft = Down | Left,
+ DownRight = Down | Right,
+ UpLeft = Up | Left,
+ UpRight = Up | Right,
+};
+
+
+// The Mode enum defines the possible states of the rotary mode selector on the joystick.
+enum Mode {
+ ModeUndefined, // It's possible to receive ModeUndefined from the joystick!
+ Mode1,
+ Mode2,
+ Mode3,
+};
+
+
+typedef unsigned int uint;
+enum Uninitialized { UNINITIALIZED };
+
+
+// BitField has little endian byte and bit order.
+template
+class BitField {
+public:
+ BitField() {
+ memset(m_Bits, 0, sizeof(m_Bits));
+ }
+
+ BitField(Uninitialized) {}
+
+ bool Bit(int index) const {
+ assert(uint(index) < NUM_BITS);
+ return bool(m_Bits[index>>3] & (1 << (index&7)));
+ }
+
+ void SetBit(int index, bool bit) {
+ if (bit)
+ SetBit(index);
+ else
+ ClearBit(index);
+ }
+
+ void SetBit(int index) {
+ assert(uint(index) < NUM_BITS);
+ m_Bits[index>>3] |= 1 << (index&7);
+ }
+
+ void ClearBit(int index) {
+ assert(uint(index) < NUM_BITS);
+ m_Bits[index>>3] &= ~(1 << (index&7));
+ }
+
+ uint UInt(int index, int width) const {
+ assert(uint(index) + uint(width) <= NUM_BITS);
+ int v = 0;
+ for (int i=0; i= 0)
+ return false;
+ // On AVR the delay is also busy but it might be able
+ // to save some power on other architectures (ARM).
+ if (poll_period_micros)
+ delayMicroseconds(poll_period_micros);
+ }
+}
+
+
+//} // namespace x52
+
+#endif
diff --git a/lib/X52-HOTAS/src/new_x52_pro.cpp b/lib/X52-HOTAS/src/new_x52_pro.cpp
new file mode 100644
index 0000000..3a1e578
--- /dev/null
+++ b/lib/X52-HOTAS/src/new_x52_pro.cpp
@@ -0,0 +1,621 @@
+#include "new_x52_pro.h"
+
+
+inline void SetUInt(uint32_t b, uint8_t index, uint8_t size, uint8_t value) {
+ for (uint8_t i = 0; i> i) & 1);
+}
+
+inline void SetBit(uint32_t b, uint8_t index, bool value) {
+ bitWrite(b, index, value);
+}
+
+
+inline void JoystickConfig::SetFromBinary(const Binary& b) {
+ led_brightness = uint8_t(b.UInt(0, 5));
+ pov_1_led_blinking = b.Bit(5);
+ button_a_led = LEDColor(b.UInt(6, 2));
+ pov_2_led = LEDColor(b.UInt(8, 2));
+ button_fire_led = !b.Bit(10);
+ button_b_led = LEDColor(b.UInt(11, 2));
+ button_t1_t2_led = LEDColor(b.UInt(13, 2));
+ button_t3_t4_led = LEDColor(b.UInt(15, 2));
+ button_t5_t6_led = LEDColor(b.UInt(17, 2));
+}
+
+
+inline void JoystickConfig::ToBinary(Binary& b) const {
+ b.SetUInt(0, 5, led_brightness);
+ b.SetBit(5, pov_1_led_blinking);
+ b.SetUInt(6, 2, button_a_led);
+ b.SetUInt(8, 2, pov_2_led);
+ b.SetBit(10, !button_fire_led);
+ b.SetUInt(11, 2, button_b_led);
+ b.SetUInt(13, 2, button_t1_t2_led);
+ b.SetUInt(15, 2, button_t3_t4_led);
+ b.SetUInt(17, 2, button_t5_t6_led);
+}
+
+
+inline void JoystickState::SetFromBinary(const Binary& b) {
+ x = uint16_t(b.UInt(0, 8) | (b.UInt(16, 2) << 8));
+ y = uint16_t(b.UInt(8, 8) | (b.UInt(18, 2) << 8));
+ z = uint16_t(b.UInt(24, 8) | (b.UInt(22, 2) << 8));
+
+ switch (b.UInt(32, 4)) {
+ case 1: pov_1 = Down; break;
+ case 2: pov_1 = DownRight; break;
+ case 3: pov_1 = Right; break;
+ case 4: pov_1 = UpRight; break;
+ case 5: pov_1 = Up; break;
+ case 6: pov_1 = UpLeft; break;
+ case 7: pov_1 = Left; break;
+ case 8: pov_1 = DownLeft; break;
+ default: pov_1 = NoDirection; break;
+ }
+
+ pov_2 = Direction(
+ (-b.Bit(36) & Up) |
+ (-b.Bit(37) & Right) |
+ (-b.Bit(38) & Down) |
+ (-b.Bit(39) & Left)
+ );
+
+ switch (b.UInt(45, 3)) {
+ case 1: mode = Mode1; break;
+ case 2: mode = Mode2; break;
+ case 4: mode = Mode3; break;
+ default: mode = ModeUndefined; break;
+ }
+
+ trigger_stage_1 = b.Bit(40);
+ button_fire = b.Bit(41);
+ button_a = b.Bit(42);
+ button_c = b.Bit(43);
+ trigger_stage_2 = b.Bit(44);
+ button_b = b.Bit(48);
+ pinkie_switch = b.Bit(49);
+ button_t1 = b.Bit(50);
+ button_t2 = b.Bit(51);
+ button_t3 = b.Bit(52);
+ button_t4 = b.Bit(53);
+ button_t5 = b.Bit(54);
+ button_t6 = b.Bit(55);
+}
+inline void JoystickState::SetFromBinary2(const uint64_t b) {
+
+ SetUInt((uint32_t)x,0,8,b);
+ SetUInt((uint32_t)x,16,2,(b>>15)&3);
+
+ SetUInt((uint32_t)y,8,8,b);
+ SetUInt((uint32_t)y,18,2,(b>>17)&3);
+
+ SetUInt((uint32_t)z,24,8,b);
+ SetUInt((uint32_t)z,22,2,(b>>21)&3);
+
+ //x = uint16_t(b.UInt(0, 8) | (b.UInt(16, 2) << 8));
+ //y = uint16_t(b.UInt(8, 8) | (b.UInt(18, 2) << 8));
+ //z = uint16_t(b.UInt(24, 8) | (b.UInt(22, 2) << 8));
+
+ uint8_t pov = 0;
+ SetUInt((uint32_t)pov,32,4,(b>>31)&0xf);
+
+ switch (pov) {
+ case 1: pov_1 = Down; break;
+ case 2: pov_1 = DownRight; break;
+ case 3: pov_1 = Right; break;
+ case 4: pov_1 = UpRight; break;
+ case 5: pov_1 = Up; break;
+ case 6: pov_1 = UpLeft; break;
+ case 7: pov_1 = Left; break;
+ case 8: pov_1 = DownLeft; break;
+ default: pov_1 = NoDirection; break;
+ }
+
+ pov = 0;
+ SetUInt((uint32_t)pov,36,4,(b>>35)&0xf);
+ pov_2 = Direction(
+ (bitRead(pov,0) & Up) |
+ (bitRead(pov,1) & Right) |
+ (bitRead(pov,2) & Down) |
+ (bitRead(pov,3) & Left)
+ );
+
+ //pov_2 = Direction(
+ // (-b.Bit(36) & Up) |
+ // (-b.Bit(37) & Right) |
+ // (-b.Bit(38) & Down) |
+ // (-b.Bit(39) & Left)
+ //);
+ uint8_t m = 0;
+ SetUInt((uint32_t)m,45,3,(b>>44)&3);
+
+
+ switch (m) {
+ case 1: mode = Mode1; break;
+ case 2: mode = Mode2; break;
+ case 4: mode = Mode3; break;
+ default: mode = ModeUndefined; break;
+ }
+ trigger_stage_1 = bitRead(b,40);
+ button_fire = bitRead(b,41);
+ button_a = bitRead(b,42);
+ button_c = bitRead(b,43);
+ trigger_stage_2 = bitRead(b,44);
+ button_b = bitRead(b,48);
+ pinkie_switch = bitRead(b,49);
+ button_t1 = bitRead(b,50);
+ button_t2 = bitRead(b,51);
+ button_t3 = bitRead(b,52);
+ button_t4 = bitRead(b,53);
+ button_t5 = bitRead(b,54);
+ button_t6 = bitRead(b,55);
+
+ //trigger_stage_1 = b.Bit(40);
+ //button_fire = b.Bit(41);
+ //button_a = b.Bit(42);
+ //button_c = b.Bit(43);
+ //trigger_stage_2 = b.Bit(44);
+ //button_b = b.Bit(48);
+ //pinkie_switch = b.Bit(49);
+ //button_t1 = b.Bit(50);
+ //button_t2 = b.Bit(51);
+ //button_t3 = b.Bit(52);
+ //button_t4 = b.Bit(53);
+ //button_t5 = b.Bit(54);
+ //button_t6 = b.Bit(55);
+}
+
+
+inline void JoystickState::ToBinary(Binary& b) const {
+#if X52_DEBUG
+ if (x > MAX_X) {
+ X52DebugPrint("x52::pro::JoystickState.x exceeds the maximum value. x=");
+ X52DebugPrintln(x);
+ }
+ if (y > MAX_Y) {
+ X52DebugPrint("x52::pro::JoystickState.y exceeds the maximum value. y=");
+ X52DebugPrintln(y);
+ }
+ if (z > MAX_Z) {
+ X52DebugPrint("x52::pro::JoystickState.z exceeds the maximum value. z=");
+ X52DebugPrintln(z);
+ }
+#endif
+
+ b.SetUInt(0, 8, x);
+ b.SetUInt(8, 8, y);
+ b.SetUInt(24, 8, z);
+
+ b.SetUInt(16, 2, x >> 8);
+ b.SetUInt(18, 2, y >> 8);
+ b.SetUInt(20, 2, 0);
+ b.SetUInt(22, 2, z >> 8);
+
+ uint8_t pov;
+ switch (pov_1) {
+ case Down: pov = 1; break;
+ case DownRight: pov = 2; break;
+ case Right: pov = 3; break;
+ case UpRight: pov = 4; break;
+ case Up: pov = 5; break;
+ case UpLeft: pov = 6; break;
+ case Left: pov = 7; break;
+ case DownLeft: pov = 8; break;
+ default: pov = 0; break;
+ }
+ b.SetUInt(32, 4, pov);
+
+ b.SetBit(36, bool(pov_2 & Up));
+ b.SetBit(37, bool(pov_2 & Right));
+ b.SetBit(38, bool(pov_2 & Down));
+ b.SetBit(39, bool(pov_2 & Left));
+
+ b.SetBit(40, trigger_stage_1);
+ b.SetBit(41, button_fire);
+ b.SetBit(42, button_a);
+ b.SetBit(43, button_c);
+ b.SetBit(44, trigger_stage_2);
+ b.SetBit(45, mode == Mode1);
+ b.SetBit(46, mode == Mode2);
+ b.SetBit(47, mode == Mode3);
+ b.SetBit(48, button_b);
+ b.SetBit(49, pinkie_switch);
+ b.SetBit(50, button_t1);
+ b.SetBit(51, button_t2);
+ b.SetBit(52, button_t3);
+ b.SetBit(53, button_t4);
+ b.SetBit(54, button_t5);
+ b.SetBit(55, button_t6);
+}
+
+// FakeProThrottle makes it possible to use some of your Arduino pins as a
+// connection to the PS/2 socket of an X52 Pro Joystick.
+//
+// These pin names (C01..C04) were printed on the PCB of my X52 joystick.
+// The pinout of the PS/2 connector is the same as that of the X52 non-Pro
+// but the protocol is different.
+//
+// Standard PS/2 (6-pin mini-DIN) female socket pin numbering:
+// https://en.wikipedia.org/wiki/Mini-DIN_connector#/media/File:MiniDIN-6_Connector_Pinout.svg
+//
+// PIN_C01: data output of the throttle (pin #4 of the PS/2 female socket)
+// PIN_C02: clock output of the throttle (pin #6 of the PS/2 female socket)
+// PIN_C03: data output of the joystick (pin #2 of the PS/2 female socket)
+// PIN_C04: clock output of the joystick (pin #1 of the PS/2 female socket)
+//
+// Pin #3 of the PS/2 female socket is GND.
+// Pin #5 of the PS/2 female socket is VCC.
+//
+// My X52 Pro throttle uses 4.1-4.2V for both power and GPIO but the joystick
+// works with 3.3V too.
+
+FakeProThrottle::FakeProThrottle(PIO pio, int PIN_C01, int PIN_C02, int PIN_C03, int PIN_C04) {
+ #if defined(ARDUINO_ARCH_RP2040)
+ // Find a free SM on one of the PIO's
+ sm = pio_claim_unused_sm(pio, false); // don't panic
+ // Try pio1 if SM not found
+ if (sm < 0) {
+ pio = pio1;
+ sm = pio_claim_unused_sm(pio, true); // panic if no SM is free
+ }
+ #endif
+ this->pio = pio;
+ this->PIN_C01 = PIN_C01;
+ this->PIN_C02 = PIN_C02;
+ this->PIN_C03 = PIN_C03;
+ this->PIN_C04 = PIN_C04;
+ this->PIN_C01 = PIN_C01;
+}
+
+FakeProThrottle::~FakeProThrottle() {}
+
+//template
+//lass FakeProThrottle {
+
+
+//public:
+ // Call Setup from the setup function of your Arduino project to initialize
+ // a FakeProThrottle instance.
+void FakeProThrottle::setup() {
+ pinMode(PIN_C01, OUTPUT);
+ pinMode(PIN_C02, OUTPUT);
+ pinMode(PIN_C03, INPUT);
+ pinMode(PIN_C04, INPUT);
+
+ uint offset = pio_add_program(pio, &throttle_program);
+
+ throttle_program_init(pio, sm, offset, PIN_C01, PIN_C02, PIN_C03, PIN_C04);
+
+ // On the teensy the digitalWrite seems to work only after pinMode.
+#if X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION
+ digitalWrite(PIN_C01, HIGH);
+#endif
+};
+
+
+inline bool pio_sm_put_blocking_timeout(PIO pio, uint sm, uint32_t data) {
+ check_pio_param(pio);
+ check_sm_param(sm);
+ uint32_t currentTime = millis();
+ while (pio_sm_is_tx_fifo_full(pio, sm)) {
+ if (millis() - currentTime > 100)
+ return 0;
+ }
+ pio_sm_put(pio, sm, data);
+ return 1;
+}
+inline uint32_t pio_sm_get_blocking_timeout(PIO pio, uint sm) {
+ check_pio_param(pio);
+ check_sm_param(sm);
+ uint32_t currentTime = millis();
+ while (pio_sm_is_rx_fifo_empty(pio, sm)) {
+ if (millis() - currentTime > 100)
+ return 0;
+ }
+ return pio_sm_get(pio, sm);
+}
+
+void pio_sm_print_registers(PIO pio, uint sm) {
+ Serial.printf("ctrl: 0x%x\n\r",pio->ctrl);
+ Serial.printf("fstat: 0x%x\n\r",pio->fstat);
+ Serial.printf("fdebug: 0x%x\n\r",pio->fdebug);
+ Serial.printf("flevel: 0x%x\n\r",pio->flevel);
+ Serial.printf("DBG_PADOUT: 0x%x\n\r",pio->dbg_padout);
+ Serial.printf("DBG_PADOE: 0x%x\n\r",pio->dbg_padoe);
+ Serial.print("\n\r");
+ Serial.printf("sm: %d\n\r",sm);
+ Serial.printf("clkdiv: 0x%x\n\r",pio->sm[sm].clkdiv);
+ Serial.printf(" INT: %d\n\r",(pio->sm[sm].clkdiv>>16) & 0xffff);
+ Serial.printf(" FRAC: %d\n\r",(pio->sm[sm].clkdiv>>8) & 0xff);
+ Serial.print("\n\r");
+ Serial.printf("execctrl: 0x%x\n\r",pio->sm[sm].execctrl);
+ Serial.printf(" EXEC_STALLED: %d\n\r",(pio->sm[sm].execctrl>>31) & 0x1);
+ Serial.printf(" SIDE_EN: %d\n\r",(pio->sm[sm].execctrl>>30) & 0x1);
+ Serial.printf(" SIDE_PINDIR: %d\n\r",(pio->sm[sm].execctrl>>29) & 0x1);
+ Serial.printf(" JMP_PIN: %d\n\r",(pio->sm[sm].execctrl>>24) & 0xf);
+ Serial.printf(" OUT_EN_SEL: %d\n\r",(pio->sm[sm].execctrl>>19) & 0xf);
+ Serial.printf(" INLINE_OUT_EN: %d\n\r",(pio->sm[sm].execctrl>>18) & 0x1);
+ Serial.printf(" OUT_STICKY: %d\n\r",(pio->sm[sm].execctrl>>17) & 0x1);
+ Serial.printf(" WRAP_TOP: %d\n\r",(pio->sm[sm].execctrl>>12) & 0xf);
+ Serial.printf(" WRAP_BOTTOM: %d\n\r",(pio->sm[sm].execctrl>>7) & 0xf);
+ Serial.printf(" RESERVED: %d\n\r",(pio->sm[sm].execctrl>>5) & 0x3);
+ Serial.printf(" STATUS_SEL: %d\n\r",(pio->sm[sm].execctrl>>4) & 0x1);
+ Serial.printf(" STATUS_N: %d\n\r",(pio->sm[sm].execctrl>>0) & 0xf);
+ Serial.print("\n\r");
+ Serial.printf("shiftctrl: 0x%x\n\r",pio->sm[sm].shiftctrl);
+ Serial.printf(" FJOIN_RX: %d\n\r",(pio->sm[sm].shiftctrl>>31) & 0x1);
+ Serial.printf(" FJOIN_TX: %d\n\r",(pio->sm[sm].shiftctrl>>30) & 0x1);
+
+ Serial.print(" PULL_THRESH: ");Serial.println((pio->sm[sm].shiftctrl>>25) & 0xf,BIN);
+ //Serial.printf(" PULL_THRESH: %d\n\r",(pio->sm[sm].shiftctrl>>25) & 0xf,BIN);
+ Serial.printf(" PUSH_THRESH: ");Serial.println((pio->sm[sm].shiftctrl>>20) & 0xf,BIN);
+ //Serial.printf(" PUSH_THRESH: %d\n\r",(pio->sm[sm].shiftctrl>>20) & 0xf,BIN);
+
+ Serial.printf(" OUT_SHIFTDIR: %d\n\r",(pio->sm[sm].shiftctrl>>19) & 0x1);
+ Serial.printf(" IN_SHIFTDIR: %d\n\r",(pio->sm[sm].shiftctrl>>18) & 0x1);
+ Serial.printf(" AUTOPULL: %d\n\r",(pio->sm[sm].shiftctrl>>17) & 0x1);
+ Serial.printf(" AUTOPUSH: %d\n\r",(pio->sm[sm].shiftctrl>>16) & 0x1);
+ Serial.printf(" RESERVED: %d\n\r",(pio->sm[sm].shiftctrl>>0) & 0xffff);
+ Serial.print("\n\r");
+ Serial.printf("addr: 0x%x\n\r",pio->sm[sm].addr);
+ Serial.printf(" RESERVED: %d\n\r",(pio->sm[sm].addr>>5) );
+ Serial.printf(" INSTR_ADDR: %d\n\r",(pio->sm[sm].addr>>0) & 0xf);
+ Serial.print("\n\r");
+ Serial.printf("instr: 0x%x\n\r",pio->sm[sm].instr);
+ Serial.printf(" RESERVED: %d\n\r",(pio->sm[sm].instr>>16) );
+ Serial.printf(" INSTR: %d\n\r",(pio->sm[sm].instr>>0) & 0xffff);
+ Serial.print("\n\r");
+ Serial.printf("pinctrl: 0x%x\n\r",pio->sm[sm].pinctrl);
+ Serial.printf(" SIDESET_COUNT: %d\n\r",(pio->sm[sm].pinctrl>>29) & 0x3);
+ Serial.printf(" SET_COUNT: %d\n\r",(pio->sm[sm].pinctrl>>26) & 0x3);
+ Serial.printf(" OUT_COUNT: %d\n\r",(pio->sm[sm].pinctrl>>20) & 0x3f);
+ Serial.printf(" IN_BASE: %d\n\r",(pio->sm[sm].pinctrl>>15) & 0x1f);
+ Serial.printf(" SIDESET_BASE: %d\n\r",(pio->sm[sm].pinctrl>>10) & 0x1f);
+ Serial.printf(" SET_BASE: %d\n\r",(pio->sm[sm].pinctrl>>5) & 0x1f);
+ Serial.printf(" OUT_BASE: %d\n\r",(pio->sm[sm].pinctrl>>0) & 0x1f);
+ Serial.print("\n\r");
+}
+ // PollJoystickState polls the joystick for its state. It creates a frame
+ // transmission request, waits for the joystick to respond and handles the
+ // bidirectional data transfer: sends the JoystickConfig and receives the
+ // JoystickState. Returns zero on success.
+ //
+ // A nonzero return value means error and gives the recommended number
+ // of microseconds to wait before calling PollJoystickState again.
+ // In that situation the value of the JoystickState is undefined.
+unsigned long FakeProThrottle::PollJoystickState(JoystickState& state, const JoystickConfig& cfg, unsigned long wait_micros) {
+ // PIN_C02 has to be LOW when this function returns.
+ //
+ // If X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION==1
+ // then PIN_C01 has to be HIGH when this function returns.
+
+ JoystickState::Binary recv_buf;
+ JoystickConfig::Binary send_buf;
+ //cfg.ToBinary(send_buf);
+
+ uint32_t sendbuf=0;
+ SetUInt(sendbuf, 0, 5, cfg.led_brightness);
+ SetBit(sendbuf, 5, cfg.pov_1_led_blinking);
+ SetUInt(sendbuf, 6, 2, cfg.button_a_led);
+ SetUInt(sendbuf, 8, 2, cfg.pov_2_led);
+ SetBit(sendbuf, 10, !cfg.button_fire_led);
+ SetUInt(sendbuf, 11, 2, cfg.button_b_led);
+ SetUInt(sendbuf, 13, 2, cfg.button_t1_t2_led);
+ SetUInt(sendbuf, 15, 2, cfg.button_t3_t4_led);
+ SetUInt(sendbuf, 17, 2, cfg.button_t5_t6_led);
+
+ if (!pio_sm_put_blocking_timeout(pio, sm, sendbuf)){
+ Serial.println("timeout");
+ pio_sm_print_registers(pio, sm);
+ }
+ uint64_t a = pio_sm_get_blocking_timeout(pio, sm);
+ a = (a<<32) | pio_sm_get_blocking_timeout(pio, sm);
+ if (a>0)
+ Serial.printf("0x%x\n\r", a);
+
+
+
+// // deadline for the whole frame transmission
+// unsigned long deadline = micros() + wait_micros;
+
+// // A frame consists of 76 clock pulses on both C02 and C04.
+
+// for (int i=0; i<76; i++) {
+// #if !X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION
+// // This is what the original throttle does but we have a potentially better solution.
+// if (i == 1)
+// digitalWrite(PIN_C01, HIGH);
+// else
+// #endif
+// if (i >= 57)
+// digitalWrite(PIN_C01, send_buf.Bit(i-57));
+
+// digitalWrite(PIN_C02, HIGH);
+
+// // The original joystick samples C01 here between the
+// // rising edge of C02 and the rising edge of C04.
+
+// if (!wait_for_pin_state(PIN_C04, HIGH, deadline)) {
+// X52DebugPrint("Error waiting for C04=1. Clock cycle: ");
+// X52DebugPrintln(i);
+// #if X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION
+// if (i >= 57)
+// digitalWrite(PIN_C01, HIGH);
+// #endif
+// digitalWrite(PIN_C02, LOW);
+// // Timing out with i==0 means that the joystick didn't respond to our
+// // initial C02=1 request within the available time frame defined by `wait_micros`.
+// if (i == 0)
+// return 1;
+// // We are in the middle of a frame (already started talking with the joystick).
+// // This means that the joystick will also time out and the throttle should
+// // should try to initiate a new frame only after the joystick's timeout.
+// return X52_PRO_THROTTLE_UNRESPONSIVE_MICROS;
+// }
+
+// if (i == 0)
+// // The original throttle times out if the whole frame isn't
+// // transmitted within X52_PRO_THROTTLE_TIMEOUT_MICROS
+// // measured from the first falling edge of C02.
+// // The previous deadline value was set up using `wait_micros`,
+// // that timeout applies only to the first rising edge of C04.
+// deadline = micros() + X52_PRO_THROTTLE_TIMEOUT_MICROS;
+// else if (i == 56)
+// digitalWrite(PIN_C01, LOW); // desync detection: the joystick becomes unresponsive if this isn't LOW
+// #if X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION
+// // The original throttle doesn't do this but perhaps it should
+// // because this makes desync detection more reliable.
+// // The last iteration of this for loop ends with C01=HIGH
+// // and C01 stays that way until the i==56 of the next frame.
+// else if (i >= 57)
+// digitalWrite(PIN_C01, HIGH);
+// #endif
+
+// digitalWrite(PIN_C02, LOW);
+
+// if (!wait_for_pin_state(PIN_C04, LOW, deadline)) {
+// X52DebugPrint("Error waiting for C04=0. Clock cycle: ");
+// X52DebugPrintln(i);
+// return X52_PRO_THROTTLE_UNRESPONSIVE_MICROS;
+// }
+
+// // The original throttle samples C03 here between the
+// // falling edge of C04 and the rising edge of C02.
+// if (i < JoystickState::NUM_BITS)
+// recv_buf.SetBit(i, bool(digitalRead(PIN_C03)));
+// }
+
+ state.SetFromBinary2(a);
+ //state.SetFromBinary(recv_buf);
+ return 0;
+}
+
+//void FakeProThrottle::PrepareForPoll() {
+// digitalWrite(PIN_C02, HIGH);
+//}
+
+
+// FakeProJoystick makes it possible to use some of your Arduino pins as a
+// connection to the PS/2 socket of an X52 Pro Throttle.
+//
+// The pin config is the same as that of the FakeThrottle.
+
+FakeProJoystick::FakeProJoystick(PIO pio, int PIN_C01, int PIN_C02, int PIN_C03, int PIN_C04) {
+ this->pio = pio;
+ this->PIN_C01 = PIN_C01;
+ this->PIN_C02 = PIN_C02;
+ this->PIN_C03 = PIN_C03;
+ this->PIN_C04 = PIN_C04;
+ this->PIN_C01 = PIN_C01;
+ #if defined(ARDUINO_ARCH_RP2040)
+ // Find a free SM on one of the PIO's
+ sm = pio_claim_unused_sm(pio, false); // don't panic
+ // Try pio1 if SM not found
+ if (sm < 0) {
+ pio = pio1;
+ sm = pio_claim_unused_sm(pio, true); // panic if no SM is free
+ }
+ init = true;
+ #endif
+}
+FakeProJoystick::~FakeProJoystick() {}
+
+//template
+//class FakeProJoystick {
+//public:
+ // Call Setup from the setup function of your Arduino project to initialize
+ // a FakeProJoystick instance.
+void FakeProJoystick::setup() {
+// uint offset = pio_add_program(pio, &Fake_Throttle_program);
+
+// Fake_Throttle_program_init(pio, sm, offset, PIN_C01, PIN_C02, PIN_C03, PIN_C04);
+}
+
+// SendJoystickState sends the JoystickState to the throttle and receives
+// the JoystickConfig. On the other side there must be a throttle polling/waiting
+// for the JoystickState. Returns zero on success.
+//
+// A nonzero return value means error and gives the number of microseconds
+// to wait before calling SendJoystickState again. In that situation the
+// value of the JoystickConfig is undefined.
+unsigned long FakeProJoystick::SendJoystickState(const JoystickState& state, JoystickConfig& cfg, unsigned long wait_micros) {
+ // waiting for the throttle's poll
+ if (!wait_for_pin_state(PIN_C02, HIGH, micros()+wait_micros))
+ return 1;
+
+ JoystickConfig::Binary recv_buf;
+ JoystickState::Binary send_buf;
+ state.ToBinary(send_buf);
+
+ auto deadline = micros() + X52_PRO_JOYSTICK_TIMEOUT_MICROS;
+
+ // A frame consists of 76 clock pulses on both C02 and C04.
+ for (int i=0; i<76; i++) {
+ if (i < JoystickState::NUM_BITS)
+ digitalWrite(PIN_C03, send_buf.Bit(i));
+ else if (i >= 57)
+ // The original joystick samples C01 here between the
+ // rising edge of C02 and the rising edge of C04.
+ recv_buf.SetBit(i-57, bool(digitalRead(PIN_C01)));
+
+ digitalWrite(PIN_C04, HIGH);
+
+ if (!wait_for_pin_state(PIN_C02, LOW, deadline)) {
+ X52DebugPrint("Error waiting for C02=0. Clock cycle: ");
+ X52DebugPrintln(i);
+ digitalWrite(PIN_C04, LOW);
+ return X52_PRO_JOYSTICK_UNRESPONSIVE_MICROS;
+ }
+
+#if X52_PRO_IMPROVED_THROTTLE_CLIENT_DESYNC_DETECTION
+ if (i >= 1 && i <= 55) {
+ // This is something that the original joystick doesn't do.
+ // This method leads to very quick and reliable desync detection.
+ // It's based on the assumption that the X52 Pro always sends
+ // ones over C01 while the joystick is sending its state over C03.
+ if (!digitalRead(PIN_C01)) {
+ X52DebugPrint("Desync detected: bits 1..55 aren't all ones. Timing out to force a resync. Clock cycle: ");
+ X52DebugPrintln(i);
+ digitalWrite(PIN_C04, LOW);
+ return X52_PRO_JOYSTICK_DESYNC_UNRESPONSIVE_MICROS;
+ }
+ } else
+#endif
+ if (i == 56) {
+ // This is something that the original joystick also does.
+ if (digitalRead(PIN_C01)) {
+ X52DebugPrintln("Desync detected: bit 56 isn't zero. Timing out to force a resync.");
+ digitalWrite(PIN_C04, LOW);
+ return X52_PRO_JOYSTICK_DESYNC_UNRESPONSIVE_MICROS;
+ }
+ }
+
+ digitalWrite(PIN_C04, LOW);
+
+ // The original throttle samples C03 here between the
+ // falling edge of C04 and the rising edge of C02.
+
+ if (!wait_for_pin_state(PIN_C02, HIGH, deadline)) {
+ X52DebugPrint("Error waiting for C02=1. Clock cycle: ");
+ X52DebugPrintln(i);
+ return X52_PRO_JOYSTICK_UNRESPONSIVE_MICROS;
+ }
+ }
+
+ cfg.SetFromBinary(recv_buf);
+ return 0;
+}
+
+// IsPollInProgress returns true if the throttle is waiting for the
+// JoystickState on the other side of the connection. In that situation
+// a call to SendJoystickState is less likely to block in a waiting state
+// (or fail as a result of wait timeout).
+bool FakeProJoystick::IsPollInProgress() {
+ return bool(digitalRead(PIN_C02));
+}
+
+
+
+//} // namespace pro
+//} // namespace x52
diff --git a/lib/X52-HOTAS/src/new_x52_pro.h b/lib/X52-HOTAS/src/new_x52_pro.h
new file mode 100644
index 0000000..4ba4391
--- /dev/null
+++ b/lib/X52-HOTAS/src/new_x52_pro.h
@@ -0,0 +1,184 @@
+#ifndef X52_PRO
+#define X52_PRO
+
+// This value is hardcoded into the firmware of my original X52 Pro throttle.
+#ifndef X52_PRO_THROTTLE_TIMEOUT_MICROS
+ #define X52_PRO_THROTTLE_TIMEOUT_MICROS 17000
+#endif
+
+// This value is hardcoded into the firmware of my original X52 Pro joystick.
+#ifndef X52_PRO_JOYSTICK_TIMEOUT_MICROS
+ #define X52_PRO_JOYSTICK_TIMEOUT_MICROS 23000
+#endif
+
+#ifndef X52_PRO_THROTTLE_UNRESPONSIVE_MICROS
+ #define X52_PRO_THROTTLE_UNRESPONSIVE_MICROS (X52_PRO_JOYSTICK_TIMEOUT_MICROS + 5000)
+#endif
+
+// This value is hardcoded into the firmware of my original X52 Pro joystick.
+#ifndef X52_PRO_JOYSTICK_UNRESPONSIVE_MICROS
+ #define X52_PRO_JOYSTICK_UNRESPONSIVE_MICROS 2000
+#endif
+
+// This value is hardcoded into the firmware of my original X52 Pro joystick.
+// It has to be greater than X52_PRO_THROTTLE_TIMEOUT_MICROS.
+#ifndef X52_PRO_JOYSTICK_DESYNC_UNRESPONSIVE_MICROS
+ #define X52_PRO_JOYSTICK_DESYNC_UNRESPONSIVE_MICROS 23000
+#endif
+
+// Enabling this feature allows the FakeProJoystick to behave differently from
+// the original joystick in order to make the desync detection more reliable.
+#ifndef X52_PRO_IMPROVED_THROTTLE_CLIENT_DESYNC_DETECTION
+ #define X52_PRO_IMPROVED_THROTTLE_CLIENT_DESYNC_DETECTION 0
+#endif
+
+// Enabling this feature allows the FakeProThrottle to behave differently from
+// the original throttle in order to make the desync detection more reliable.
+#ifndef X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION
+ #define X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION 0
+#endif
+
+#ifndef X52_PRO_DEFAULT_POLL_JOYSTICK_STATE_WAIT_MICROS
+ #define X52_PRO_DEFAULT_POLL_JOYSTICK_STATE_WAIT_MICROS 25000
+#endif
+
+#ifndef X52_PRO_DEFAULT_SEND_JOYSTICK_STATE_WAIT_MICROS
+ #define X52_PRO_DEFAULT_SEND_JOYSTICK_STATE_WAIT_MICROS 25000
+#endif
+
+#include "new_x52_common.h"
+#include "throttle-protocol.pio.h"
+
+
+
+enum LEDColor {
+ Amber = 0, // 00
+ Green = 1, // 10
+ Red = 2, // 01
+ Off = 3, // 11
+};
+
+
+// JoystickState is the data sent by the joystick through the PS/2 cable.
+struct JoystickState {
+ static constexpr uint16_t MAX_X = 1023;
+ static constexpr uint16_t MAX_Y = 1023;
+ static constexpr uint16_t MAX_Z = 1023;
+
+ static constexpr uint16_t CENTER_X = 512;
+ static constexpr uint16_t CENTER_Y = 512;
+ static constexpr uint16_t CENTER_Z = 512;
+
+ uint16_t x; // valid_range: 0..1023(MAX_X) center: 512(CENTER_X)
+ uint16_t y; // valid_range: 0..1023(MAX_Y) center: 512(CENTER_Y)
+ uint16_t z; // valid_range: 0..1023(MAX_Z) center: 512(CENTER_Z)
+
+ Direction pov_1;
+ Direction pov_2;
+ Mode mode;
+
+ bool trigger_stage_1: 1;
+ bool trigger_stage_2: 1;
+ bool pinkie_switch: 1;
+ bool button_fire: 1;
+ bool button_a: 1;
+ bool button_b: 1;
+ bool button_c: 1;
+ bool button_t1: 1;
+ bool button_t2: 1;
+ bool button_t3: 1;
+ bool button_t4: 1;
+ bool button_t5: 1;
+ bool button_t6: 1;
+
+ JoystickState() {
+ memset(this, 0, sizeof(*this));
+ }
+
+ // Constructor for the pros who believe they know what they are doing.
+ JoystickState(Uninitialized) {}
+
+ static constexpr int NUM_BITS = 56;
+ typedef BitField Binary;
+
+ void SetFromBinary(const Binary&);
+ void SetFromBinary2(const uint64_t);
+ void ToBinary(Binary&) const;
+};
+
+
+// JoystickConfig is the data sent by the throttle through the PS/2 cable.
+struct JoystickConfig {
+ static constexpr uint8_t MAX_LED_BRIGHTNESS = 31;
+
+ uint8_t led_brightness; // valid range: 0..31 (MAX_LED_BRIGHTNESS)
+ bool pov_1_led_blinking; // blinks about 4 times per second
+ bool button_fire_led;
+
+ LEDColor pov_2_led: 2;
+ LEDColor button_a_led: 2;
+ LEDColor button_b_led: 2;
+ LEDColor button_t1_t2_led: 2;
+ LEDColor button_t3_t4_led: 2;
+ LEDColor button_t5_t6_led: 2;
+
+ JoystickConfig() {
+ led_brightness = MAX_LED_BRIGHTNESS;
+ pov_1_led_blinking = false;
+ button_fire_led = true;
+ pov_2_led = Green;
+ button_a_led = Green;
+ button_b_led = Green;
+ button_t1_t2_led = Green;
+ button_t3_t4_led = Green;
+ button_t5_t6_led = Green;
+ }
+
+ // Constructor for the pros who believe they know what they are doing.
+ JoystickConfig(Uninitialized) {}
+
+ static constexpr int NUM_BITS = 19;
+ typedef BitField Binary;
+
+ void SetFromBinary(const Binary&);
+ void ToBinary(Binary&) const;
+};
+
+class FakeProThrottle {
+private:
+ int sm;
+ PIO pio;
+ int PIN_C01;
+ int PIN_C02;
+ int PIN_C03;
+ int PIN_C04;
+ bool init = false;
+
+ /* data */
+public:
+ FakeProThrottle(PIO pio, int PIN_C01, int PIN_C02, int PIN_C03, int PIN_C04 /* args */);
+ ~FakeProThrottle();
+ void setup();
+ unsigned long PollJoystickState(JoystickState& state, const JoystickConfig& cfg, unsigned long wait_micros=X52_PRO_DEFAULT_POLL_JOYSTICK_STATE_WAIT_MICROS);
+ void PrepareForPoll();
+
+};
+
+class FakeProJoystick {
+private:
+ int sm;
+ PIO pio;
+ int PIN_C01;
+ int PIN_C02;
+ int PIN_C03;
+ int PIN_C04;
+ bool init = false;
+public:
+ FakeProJoystick(PIO pio, int PIN_C01, int PIN_C02, int PIN_C03, int PIN_C04 /* args */);
+ ~FakeProJoystick();
+ void setup();
+ unsigned long SendJoystickState(const JoystickState& state, JoystickConfig& cfg, unsigned long wait_micros=X52_PRO_DEFAULT_SEND_JOYSTICK_STATE_WAIT_MICROS);
+ bool IsPollInProgress();
+};
+
+#endif
diff --git a/lib/X52-HOTAS/src/new_x52_std.cpp b/lib/X52-HOTAS/src/new_x52_std.cpp
new file mode 100644
index 0000000..c4c0968
--- /dev/null
+++ b/lib/X52-HOTAS/src/new_x52_std.cpp
@@ -0,0 +1,289 @@
+#include "new_x52_std.h"
+
+FakeStdThrottle::FakeStdThrottle(PIO pio, int PIN_C01, int PIN_C02, int PIN_C03, int PIN_C04) {
+ pio = this->pio;
+ PIN_C01 = this->PIN_C01;
+ PIN_C02 = this->PIN_C02;
+ PIN_C03 = this->PIN_C03;
+ PIN_C04 = this->PIN_C04;
+ PIN_C01 = this->PIN_C01;
+ #if defined(ARDUINO_ARCH_RP2040)
+ // Find a free SM on one of the PIO's
+ sm = pio_claim_unused_sm(pio, false); // don't panic
+ // Try pio1 if SM not found
+ if (sm < 0) {
+ pio = pio1;
+ sm = pio_claim_unused_sm(pio, true); // panic if no SM is free
+ }
+ init = true;
+ #endif
+}
+
+FakeStdThrottle::~FakeStdThrottle() {}
+//template >
+//class FakeStdThrottle {
+//public:
+ // Call Setup from the setup function of your Arduino project to initialize
+ // a FakeStdThrottle instance.
+ void FakeStdThrottle::setup() {
+ pinMode(PIN_C01, OUTPUT);
+ // The value of C01 is allowed to be anything between frames (undefined).
+ // digitalWrite(PIN_C01, LOW);
+ pinMode(PIN_C02, OUTPUT);
+ // On the teensy the digitalWrite seems to work only after pinMode.
+ digitalWrite(PIN_C02, LOW);
+ pinMode(PIN_C03, INPUT);
+ pinMode(PIN_C04, INPUT);
+ //m_PulseWaiter.Setup();
+ }
+
+// PollJoystickState polls the joystick for its state. It creates a frame
+// transmission request, waits for the joystick to respond and handles the
+// bidirectional data transfer: sends the JoystickConfig and receives the
+// JoystickState. Returns zero on success.
+//
+// A nonzero return value means error and gives the recommended number
+// of microseconds to wait before calling PollJoystickState again.
+// In that situation the value of the JoystickState is undefined.
+//
+// My X52 joystick is willing to send its state at most ~50 times per second.
+unsigned long FakeStdThrottle::PollJoystickState(JoystickState& state, const JoystickConfig& cfg, unsigned long wait_micros) {
+ // Note: PIN_C02 has to be LOW when this function returns.
+
+ {
+ // deadline for the initial response
+ unsigned long wait_deadline = micros()+wait_micros;
+
+ if (!wait_for_pin_state(PIN_C04, LOW, wait_deadline))
+ return 1;
+
+ // The original joystick's C04 pulse seems to be at least 15us long.
+
+ //auto trigger = [](){
+ // digitalWrite(PIN_C02, HIGH);
+ //};
+ //auto wait_res = m_PulseWaiter.WaitForPulse(wait_deadline, trigger);
+ //if (wait_res != PulseFinished) {
+ // X52DebugPrintln("Timed out while waiting for the C04 pulse before receiving the joystick state.");
+ // digitalWrite(PIN_C02, LOW);
+ // return (wait_res == PulseNotStarted) ? 1 : X52_THROTTLE_UNRESPONSIVE_MICROS;
+ //}
+ }
+
+ // deadline for the whole frame transmission
+ unsigned long deadline = micros() + X52_THROTTLE_TIMEOUT_MICROS;
+
+ JoystickState::Binary recv_buf;
+
+ for (int i=0; i<(JoystickState::NUM_BITS-1); i++) {
+
+ // I don't have an X52 throttle to test this but the throttle must
+ // be sampling C03 between falling-C04 and falling-C02.
+ // The other sensible option (between rising-C04 and rising-C02)
+ // wouldn't work because the joystick often removes the data bit
+ // from C03 before the rising-C02 edge.
+ recv_buf.SetBit(i, bool(digitalRead(PIN_C03)));
+
+ digitalWrite(PIN_C02, LOW);
+
+ if (!wait_for_pin_state(PIN_C04, HIGH, deadline)) {
+ X52DebugPrint("Error waiting for C04=1 while receiving the joystick state. Clock cycle: ");
+ X52DebugPrintln(i);
+ digitalWrite(PIN_C02, LOW);
+ return X52_THROTTLE_UNRESPONSIVE_MICROS;
+ }
+
+ digitalWrite(PIN_C02, HIGH);
+
+ if (!wait_for_pin_state(PIN_C04, LOW, deadline)) {
+ X52DebugPrint("Error waiting for C04=0 while receiving the joystick state. Clock cycle: ");
+ X52DebugPrintln(i);
+ digitalWrite(PIN_C02, LOW);
+ return X52_THROTTLE_UNRESPONSIVE_MICROS;
+ }
+ }
+ recv_buf.SetBit(JoystickState::NUM_BITS-1, bool(digitalRead(PIN_C03)));
+
+ // The original joystick's C04 pulse seems to be at least 50us long.
+
+ //auto trigger = [](){
+ // digitalWrite(PIN_C02, LOW);
+ //};
+ //auto wait_res = m_PulseWaiter.WaitForPulse(deadline, trigger);
+ //if (wait_res != PulseFinished) {
+ // X52DebugPrintln("Timed out while waiting for the C04 pulse before sending the joystick config.");
+ // return X52_THROTTLE_UNRESPONSIVE_MICROS;
+ //}
+
+ JoystickConfig::Binary send_buf;
+ cfg.ToBinary(send_buf);
+
+ for (int i=0; i
+//class FakeStdJoystick {
+//public:
+FakeStdJoystick::FakeStdJoystick(PIO pio, int PIN_C01, int PIN_C02, int PIN_C03, int PIN_C04) {
+ pio = this->pio;
+ PIN_C01 = this->PIN_C01;
+ PIN_C02 = this->PIN_C02;
+ PIN_C03 = this->PIN_C03;
+ PIN_C04 = this->PIN_C04;
+ PIN_C01 = this->PIN_C01;
+ #if defined(ARDUINO_ARCH_RP2040)
+ // Find a free SM on one of the PIO's
+ sm = pio_claim_unused_sm(pio, false); // don't panic
+ // Try pio1 if SM not found
+ if (sm < 0) {
+ pio = pio1;
+ sm = pio_claim_unused_sm(pio, true); // panic if no SM is free
+ }
+ init = true;
+ #endif
+}
+
+FakeStdJoystick::~FakeStdJoystick() {}
+
+// Call Setup from the setup function of your Arduino project to initialize
+// a FakeStdJoystick instance.
+void FakeStdJoystick::setup() {
+ pinMode(PIN_C01, INPUT);
+ pinMode(PIN_C02, INPUT);
+ pinMode(PIN_C03, OUTPUT);
+ pinMode(PIN_C04, OUTPUT);
+ // On the teensy the digitalWrite seems to work only after pinMode.
+ digitalWrite(PIN_C04, LOW);
+}
+
+// SendJoystickState sends the JoystickState to the throttle and receives
+// the JoystickConfig. On the other side there must be a throttle polling/waiting
+// for the JoystickState. Returns zero on success.
+//
+// A nonzero return value means error and gives the number of microseconds
+// to wait before calling SendJoystickState again. In that situation the
+// value of the JoystickConfig is undefined.
+unsigned long FakeStdJoystick::SendJoystickState(const JoystickState& state, JoystickConfig& cfg, unsigned long wait_micros) {
+ if (!wait_for_pin_state(PIN_C02, HIGH, micros()+wait_micros))
+ return 1;
+
+ JoystickState::Binary send_buf;
+ state.ToBinary(send_buf);
+
+ auto deadline = micros() + X52_JOYSTICK_TIMEOUT_MICROS;
+
+ // The first data bit has to be on C03 before the falling edge of C04
+ digitalWrite(PIN_C03, send_buf.Bit(0));
+
+ // The first C04 pulse that doesn't require an ACK from the throttle
+ digitalWrite(PIN_C04, HIGH);
+ // The original joystick uses a >=15us pulse and I don't have a throttle to test shorter pulses.
+ delayMicroseconds(X52_FIRST_C04_PULSE_MICROS);
+ digitalWrite(PIN_C04, LOW);
+
+ // The throttle samples C03 for the first data bit here between falling-C04 and falling-C02.
+
+ if (!wait_for_pin_state(PIN_C02, LOW, deadline)) {
+ X52DebugPrintln("Error waiting for C02=0 while sending the first bit of the joystick state.");
+ return X52_JOYSTICK_UNRESPONSIVE_MICROS;
+ }
+
+ // sending the rest of the joystick state
+ for (int i=1; i=50us pulse and I don't have a throttle to test shorter pulses.
+ delayMicroseconds(X52_SECOND_C04_PULSE_MICROS);
+ digitalWrite(PIN_C04, LOW);
+
+ JoystickConfig::Binary recv_buf;
+
+ // receiving the config from the throttle
+ for (int i=0; i Binary;
+
+ bool SetFromBinary(const Binary&);
+ void ToBinary(Binary&) const;
+
+ static uint8_t Checksum(const Binary&);
+};
+
+
+// JoystickConfig is the data sent by the throttle through the PS/2 cable.
+struct JoystickConfig {
+ static constexpr uint8_t MAX_LED_BRIGHTNESS = 127;
+
+ uint8_t led_brightness; // valid range: 0..127 (MAX_LED_BRIGHTNESS)
+ bool pov_1_led_blinking; // blinks about 25 times per second
+
+ JoystickConfig() {
+ led_brightness = MAX_LED_BRIGHTNESS;
+ pov_1_led_blinking = false;
+ }
+
+ // Constructor for the pros who believe they know what they are doing.
+ JoystickConfig(Uninitialized) {}
+
+ static constexpr int NUM_BITS = 8;
+ typedef BitField Binary;
+
+ void SetFromBinary(const Binary&);
+ void ToBinary(Binary&) const;
+};
+
+
+inline void JoystickConfig::SetFromBinary(const Binary& b) {
+ led_brightness = uint8_t(b.UInt(0, 7));
+ pov_1_led_blinking = b.Bit(7);
+}
+
+
+inline void JoystickConfig::ToBinary(Binary& b) const {
+ b.SetUInt(0, 7, led_brightness);
+ b.SetBit(7, pov_1_led_blinking);
+}
+
+
+inline bool JoystickState::SetFromBinary(const Binary& b) {
+ if (Checksum(b) != b.BufByte(7))
+ return false;
+
+ x = uint16_t(b.UInt(0, 8) | (b.UInt(16, 3) << 8));
+ y = uint16_t(b.UInt(8, 8) | (b.UInt(19, 3) << 8));
+ z = uint16_t(b.UInt(24, 8) | (b.UInt(22, 2) << 8));
+
+ switch (b.UInt(32, 4)) {
+ case 1: pov_1 = Up; break;
+ case 2: pov_1 = UpRight; break;
+ case 3: pov_1 = Right; break;
+ case 4: pov_1 = DownRight; break;
+ case 5: pov_1 = Down; break;
+ case 6: pov_1 = DownLeft; break;
+ case 7: pov_1 = Left; break;
+ case 8: pov_1 = UpLeft; break;
+ default: pov_1 = NoDirection; break;
+ }
+
+ pov_2 = Direction(
+ (-b.Bit(36) & Right) |
+ (-b.Bit(37) & Down) |
+ (-b.Bit(38) & Left) |
+ (-b.Bit(39) & Up)
+ );
+
+ switch (b.UInt(54, 2)) {
+ case 0: mode = b.Bit(47) ? Mode1 : ModeUndefined; break;
+ case 1: mode = Mode2; break;
+ case 2: mode = Mode3; break;
+ default: mode = ModeUndefined; break;
+ }
+
+ trigger_stage_1 = b.Bit(40);
+ trigger_stage_2 = b.Bit(41);
+ button_fire = b.Bit(42);
+ button_a = b.Bit(43);
+ button_b = b.Bit(44);
+ button_c = b.Bit(45);
+ pinkie_switch = b.Bit(46);
+ button_t1 = b.Bit(48);
+ button_t2 = b.Bit(49);
+ button_t3 = b.Bit(50);
+ button_t4 = b.Bit(51);
+ button_t5 = b.Bit(52);
+ button_t6 = b.Bit(53);
+
+ return true;
+}
+
+
+inline void JoystickState::ToBinary(Binary& b) const {
+#if X52_DEBUG
+ if (x > MAX_X) {
+ X52DebugPrint("x52::std::JoystickState.x exceeds the maximum value. x=");
+ X52DebugPrintln(x);
+ }
+ if (y > MAX_Y) {
+ X52DebugPrint("x52::std::JoystickState.y exceeds the maximum value. y=");
+ X52DebugPrintln(y);
+ }
+ if (z > MAX_Z) {
+ X52DebugPrint("x52::std::JoystickState.z exceeds the maximum value. z=");
+ X52DebugPrintln(z);
+ }
+#endif
+
+ b.SetUInt(0, 8, x);
+ b.SetUInt(8, 8, y);
+ b.SetUInt(24, 8, z);
+
+ b.SetUInt(16, 3, x >> 8);
+ b.SetUInt(19, 3, y >> 8);
+ b.SetUInt(22, 2, z >> 8);
+
+ uint8_t pov;
+ switch (pov_1) {
+ case Up: pov = 1; break;
+ case UpRight: pov = 2; break;
+ case Right: pov = 3; break;
+ case DownRight: pov = 4; break;
+ case Down: pov = 5; break;
+ case DownLeft: pov = 6; break;
+ case Left: pov = 7; break;
+ case UpLeft: pov = 8; break;
+ default: pov = 0; break;
+ }
+ b.SetUInt(32, 4, pov);
+
+ b.SetBit(36, bool(pov_2 & Right));
+ b.SetBit(37, bool(pov_2 & Down));
+ b.SetBit(38, bool(pov_2 & Left));
+ b.SetBit(39, bool(pov_2 & Up));
+
+ b.SetBit(47, mode == Mode1);
+ switch (mode) {
+ case Mode2: b.SetUInt(54, 2, 1); break;
+ case Mode3: b.SetUInt(54, 2, 2); break;
+ default: b.SetUInt(54, 2, 0); break;
+ }
+
+ b.SetBit(40, trigger_stage_1);
+ b.SetBit(41, trigger_stage_2);
+ b.SetBit(42, button_fire);
+ b.SetBit(43, button_a);
+ b.SetBit(44, button_b);
+ b.SetBit(45, button_c);
+ b.SetBit(46, pinkie_switch);
+ b.SetBit(48, button_t1);
+ b.SetBit(49, button_t2);
+ b.SetBit(50, button_t3);
+ b.SetBit(51, button_t4);
+ b.SetBit(52, button_t5);
+ b.SetBit(53, button_t6);
+
+ b.SetBufByte(7, Checksum(b));
+}
+
+inline uint8_t JoystickState::Checksum(const Binary& b) {
+ uint8_t chksum = b.BufByte(0);
+ for (int i=1; i<7; i++)
+ chksum ^= b.BufByte(i);
+ return chksum;
+}
+
+
+enum PulseWaitResult {
+ PulseFinished,
+ PulseStarted,
+ PulseNotStarted,
+ TooManyPulses,
+};
+
+
+// The BitBangPulseWaiter is the naive implementation that can miss a pulse
+// especially on a slower MCU. On an Arduino Micro (ATMega32U4 16MHz) this
+// implementation can miss pulses every few minutes. That results in desync
+// issues for a short period so the joystick is unresponsive for 500-1000ms
+// and the LEDs turn off for a fraction of a second.
+//
+// This bit-banging worked well on my 96MHz teensy 3.2. However, it's better
+// to be safe than sorry and use the InterruptPulseWaiter whenever possible.
+// That works well on slower MCUs too but it requires a pin that can trigger
+// interrupts on falling edges. That isn't a huge requirement. I'd use this
+// BitBangPulseWaiter only if I had no interrupt pins available (basically "never").
+// This naive implementation is still useful as a form of documentation because
+// the code explains very clearly what we want to achieve with the more
+// complicated interrupt based solution.
+template
+class BitBangPulseWaiter {
+public:
+ void Setup() {}
+
+ template
+ PulseWaitResult WaitForPulse(unsigned long deadline, PulseTriggerFunc trigger) {
+ trigger();
+ if (!wait_for_pin_state(PIN_C04, HIGH, deadline, 0))
+ return PulseNotStarted;
+ if (!wait_for_pin_state(PIN_C04, LOW, deadline, 0))
+ return PulseStarted;
+ return PulseFinished;
+ }
+};
+
+
+// The InterruptPulseWaiter attaches an interrupt handler to the C04 pin to be
+// able to reliably detect pulses. This whole "waiting for a pulse" problem
+// affects only the non-Pro joystick. My X52 Pro uses a different protocol that
+// is completely bitbang-friendly even on slower MCUs (as long as they are fast
+// enough to transmit the whole frame within 17ms).
+template
+class InterruptPulseWaiter {
+public:
+ void Setup() {
+ attachInterrupt(digitalPinToInterrupt(PIN_C04), InterruptHandler, FALLING);
+ }
+
+ template
+ PulseWaitResult WaitForPulse(unsigned long deadline, PulseTriggerFunc trigger) {
+ int c0 = Counter();
+ trigger();
+ for (;;) {
+ int c = Counter();
+ if (c != c0)
+ return (c == c0 + 1) ? PulseFinished : TooManyPulses;
+ // using delta to handle the overflows of micros()
+ unsigned long micros_left = deadline - micros();
+ if (long(micros_left) <= 0)
+ return digitalRead(PIN_C04) ? PulseStarted : PulseNotStarted;
+#if !X52_BUSY_WAIT
+ delayMicroseconds(min(10, micros_left));
+#endif
+ }
+ }
+
+private:
+ static int Counter() {
+ noInterrupts();
+ int c = m_Counter;
+ interrupts();
+ return c;
+ }
+
+ static void InterruptHandler() {
+ m_Counter++;
+ }
+
+ static volatile int m_Counter;
+};
+
+template
+volatile int InterruptPulseWaiter::m_Counter = 0;
+
+
+// FakeThrottle makes it possible to use some of your Arduino pins as a
+// connection to the PS/2 socket of an X52 (non-Pro) Joystick.
+//
+// These pin names (C01..C04) were printed on the PCB of my X52 joystick.
+// The pinout of the PS/2 connector is the same as that of the X52 Pro
+// but the protocol is different.
+//
+// Standard PS/2 (6-pin mini-DIN) female socket pin numbering:
+// https://en.wikipedia.org/wiki/Mini-DIN_connector#/media/File:MiniDIN-6_Connector_Pinout.svg
+//
+// PIN_C01: data output of the throttle (pin #4 of the PS/2 female socket)
+// PIN_C02: clock output of the throttle (pin #6 of the PS/2 female socket)
+// PIN_C03: data output of the joystick (pin #2 of the PS/2 female socket)
+// PIN_C04: clock output of the joystick (pin #1 of the PS/2 female socket)
+//
+// Pin #3 of the PS/2 female socket is GND.
+// Pin #5 of the PS/2 female socket is VCC.
+//
+// My joystick claims to be 5V 500mW but works with 3.3V too.
+//template < typename PulseWaiter=InterruptPulseWaiter>
+class FakeStdThrottle {
+private:
+ //InterruptPulseWaiter m_PulseWaiter;
+ uint8_t PIN_C01;
+ uint8_t PIN_C02;
+ uint8_t PIN_C03;
+ uint8_t PIN_C04;
+ PIO pio;
+ uint8_t sm;
+ bool init = false;
+public:
+ FakeStdThrottle(PIO pio, int PIN_C01, int PIN_C02, int PIN_C03, int PIN_C04);//, PulseWaiter InterruptPulseWaiter /* args */);
+ ~FakeStdThrottle();
+ void setup();
+ unsigned long PollJoystickState(JoystickState& state, const JoystickConfig& cfg, unsigned long wait_micros=X52_DEFAULT_POLL_JOYSTICK_STATE_WAIT_MICROS);
+
+};
+
+class FakeStdJoystick {
+private:
+ uint8_t PIN_C01;
+ uint8_t PIN_C02;
+ uint8_t PIN_C03;
+ uint8_t PIN_C04;
+ PIO pio;
+ uint8_t sm;
+ bool init = false;
+public:
+ FakeStdJoystick(PIO pio, int PIN_C01, int PIN_C02, int PIN_C03, int PIN_C04);//, PulseWaiter InterruptPulseWaiter /* args */);
+ ~FakeStdJoystick();
+ void setup();
+ unsigned long SendJoystickState(const JoystickState& state, JoystickConfig& cfg, unsigned long wait_micros=X52_DEFAULT_SEND_JOYSTICK_STATE_WAIT_MICROS);
+ bool IsPollInProgress();
+};
+
+
+#endif
\ No newline at end of file
diff --git a/lib/X52-HOTAS/src/new_x52_util.h b/lib/X52-HOTAS/src/new_x52_util.h
new file mode 100644
index 0000000..7014d94
--- /dev/null
+++ b/lib/X52-HOTAS/src/new_x52_util.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include
+
+
+
+template
+class RateLogger {
+public:
+ RateLogger(): m_NumUpdates(0), m_PrevLogTime(0) {}
+
+ void OnUpdate() {
+ m_NumUpdates++;
+ unsigned long now = millis();
+ // using delta to handle the overflows of millis()
+ unsigned long elapsed = now - m_PrevLogTime;
+ if (elapsed < LOG_PERIOD_MILLIS)
+ return;
+ Serial.print("Updates per second: ");
+ Serial.println(double(m_NumUpdates) / double(elapsed) * 1000.0);
+ m_NumUpdates = 0;
+ m_PrevLogTime = now;
+ }
+
+private:
+ unsigned long m_NumUpdates;
+ unsigned long m_PrevLogTime;
+};
+
+
+// Rate limiter with a history buffer to be able to deal with some jitter.
+// A lower NUM_STORED_TIMESTAMPS value reduces the memory consumption but
+// makes the RateLimiter less effective at dealing with jitter.
+template
+class RateLimiter {
+public:
+ RateLimiter() {
+ m_Index = 0;
+ memset(m_UpdateTimes, 0, sizeof(m_UpdateTimes));
+ }
+
+ unsigned long MicrosTillNextUpdate() {
+ unsigned long now = micros();
+ // using delta to handle the overflows of micros()
+ unsigned long micros_left = m_UpdateTimes[m_Index] - now;
+ if (long(micros_left) > 0)
+ return micros_left;
+ m_UpdateTimes[m_Index] = now + g_StoredPeriod;
+ m_Index = (m_Index + 1) % NUM_STORED_TIMESTAMPS;
+ m_UpdateTimes[m_Index] = min(m_UpdateTimes[m_Index], now + g_OneUpdatePeriod);
+ return 0;
+ }
+
+private:
+ int m_Index;
+ unsigned long m_UpdateTimes[NUM_STORED_TIMESTAMPS];
+
+ static constexpr unsigned long g_OneUpdatePeriod = (1000000 + MAX_UPDATES_PER_SECOND/2) / MAX_UPDATES_PER_SECOND;
+ static constexpr unsigned long g_StoredPeriod = (NUM_STORED_TIMESTAMPS*1000000 + MAX_UPDATES_PER_SECOND/2) / MAX_UPDATES_PER_SECOND;
+};
diff --git a/lib/X52-HOTAS/src/throttle-protocol.pio b/lib/X52-HOTAS/src/throttle-protocol.pio
new file mode 100644
index 0000000..c64fc02
--- /dev/null
+++ b/lib/X52-HOTAS/src/throttle-protocol.pio
@@ -0,0 +1,63 @@
+.program throttle
+.side_set 1 opt
+
+.wrap_target
+ mov x, y
+read_loop:
+ wait 1 pin 1 [1] side 1 ; wait for 1 on pin ClockOut and side_set pin 2 to 1
+ wait 0 pin 1 [1] side 0 ; wait for 0 on pin ClockOut and side_set pin 2 to 0
+ in pins 1
+ jmp x-- read_loop
+ push
+
+ wait 1 pin 1 [1] side 1
+ set pins, 1
+ wait 0 pin 1 [1] side 0
+ set pins, 0
+
+ set x, 18 ; loop 19 times for writing bits
+write_loop:
+ wait 1 pin 1 [1] side 1 ; wait for 1 on pin ClockOut and side_set pin 2 to 1
+ wait 0 pin 1 [1] side 0 ; wait for 0 on pin ClockOut and side_set pin 2 to 0
+ out pins, 1
+ jmp x-- write_loop
+.wrap
+
+% c-sdk {
+
+#include "pico/stdlib.h"
+#include "hardware/pio.h"
+static inline void throttle_program_init(PIO pio, uint sm, uint offset, uint DataOut, uint ClockOut, uint DataIn, uint ClockIn) {
+
+ // Configure state machine
+ pio_sm_config config = throttle_program_get_default_config(offset);
+
+ sm_config_set_in_shift(&config, false, true, 28);
+ sm_config_set_out_shift(&config, false, true, 31);
+
+ // Map pins
+ sm_config_set_out_pins(&config, DataOut, 1);
+ sm_config_set_set_pins(&config, DataOut, 1);
+ sm_config_set_in_pins(&config, DataIn);
+ sm_config_set_sideset_pins(&config, ClockOut);
+
+ // Set pin directions
+ pio_sm_set_consecutive_pindirs(pio, sm, DataOut, 1, true);
+ pio_sm_set_consecutive_pindirs(pio, sm, ClockOut, 1, true);
+ pio_sm_set_consecutive_pindirs(pio, sm, DataIn, 1, false);
+ pio_sm_set_consecutive_pindirs(pio, sm, ClockIn, 1, false);
+
+ // Side-set options
+ sm_config_set_sideset(&config, 1, true, false); // 1 side-set pin, optional, enable side-set
+
+ // Set variable for loop
+ pio_sm_put(pio, sm, 55);
+ pio_sm_exec(pio, sm, pio_encode_pull(false, false));
+ pio_sm_exec(pio, sm, pio_encode_mov(pio_y,pio_osr));
+
+ // Initialize state machine
+ pio_sm_init(pio, sm, offset, &config);
+ pio_sm_set_enabled(pio, sm, true);
+}
+
+%}
\ No newline at end of file
diff --git a/lib/X52-HOTAS/src/throttle-protocol.pio.h b/lib/X52-HOTAS/src/throttle-protocol.pio.h
new file mode 100644
index 0000000..959926d
--- /dev/null
+++ b/lib/X52-HOTAS/src/throttle-protocol.pio.h
@@ -0,0 +1,69 @@
+// -------------------------------------------------- //
+// This file is autogenerated by pioasm; do not edit! //
+// -------------------------------------------------- //
+
+#pragma once
+
+#if !PICO_NO_HARDWARE
+#include "hardware/pio.h"
+#endif
+
+// -------- //
+// throttle //
+// -------- //
+
+#define throttle_wrap_target 0
+#define throttle_wrap 3
+
+static const uint16_t throttle_program_instructions[] = {
+ // .wrap_target
+ 0xa022, // 0: mov x, y
+ 0x3d21, // 1: wait 0 pin, 1 side 1 [5]
+ 0x35a1, // 2: wait 1 pin, 1 side 0 [5]
+ 0x0001, // 3: jmp 1
+ // .wrap
+};
+
+#if !PICO_NO_HARDWARE
+static const struct pio_program throttle_program = {
+ .instructions = throttle_program_instructions,
+ .length = 4,
+ .origin = -1,
+};
+
+static inline pio_sm_config throttle_program_get_default_config(uint offset) {
+ pio_sm_config c = pio_get_default_sm_config();
+ sm_config_set_wrap(&c, offset + throttle_wrap_target, offset + throttle_wrap);
+ sm_config_set_sideset(&c, 2, true, false);
+ return c;
+}
+
+#include "pico/stdlib.h"
+#include "hardware/pio.h"
+static inline void throttle_program_init(PIO pio, uint sm, uint offset, uint DataOut, uint ClockOut, uint DataIn, uint ClockIn) {
+ // Configure state machine
+ pio_sm_config config = throttle_program_get_default_config(offset);
+ sm_config_set_in_shift(&config, false, true, 28);
+ sm_config_set_out_shift(&config, false, true, 31);
+ // Map pins
+ sm_config_set_out_pins(&config, DataOut, 1);
+ sm_config_set_set_pins(&config, DataOut, 2);
+ sm_config_set_in_pins(&config, DataIn);
+ sm_config_set_sideset_pins(&config, ClockOut);
+ // Set pin directions
+ pio_sm_set_consecutive_pindirs(pio, sm, DataOut, 1, true);
+ pio_sm_set_consecutive_pindirs(pio, sm, ClockOut, 1, true);
+ pio_sm_set_consecutive_pindirs(pio, sm, DataIn, 1, false);
+ pio_sm_set_consecutive_pindirs(pio, sm, ClockIn, 1, false);
+ // Side-set options
+ sm_config_set_sideset(&config, 1, true, false); // 1 side-set pin, optional, enable side-set
+ // Set variable for loop
+ pio_sm_put(pio, sm, 55);
+ pio_sm_exec(pio, sm, pio_encode_pull(false, false));
+ pio_sm_exec(pio, sm, pio_encode_mov(pio_y,pio_osr));
+ // Initialize state machine
+ pio_sm_init(pio, sm, offset, &config);
+ pio_sm_set_enabled(pio, sm, true);
+}
+
+#endif
diff --git a/lib/X52-HOTAS/src/x52_pro.h b/lib/X52-HOTAS/src/x52_pro.h
index 4c2f08e..4710d0d 100644
--- a/lib/X52-HOTAS/src/x52_pro.h
+++ b/lib/X52-HOTAS/src/x52_pro.h
@@ -28,13 +28,13 @@
#define X52_PRO_JOYSTICK_DESYNC_UNRESPONSIVE_MICROS 23000
#endif
-// Enabling this feature allows the ThrottleClient to behave differently from
+// Enabling this feature allows the FakeJoystick to behave differently from
// the original joystick in order to make the desync detection more reliable.
#ifndef X52_PRO_IMPROVED_THROTTLE_CLIENT_DESYNC_DETECTION
#define X52_PRO_IMPROVED_THROTTLE_CLIENT_DESYNC_DETECTION 0
#endif
-// Enabling this feature allows the JoystickClient to behave differently from
+// Enabling this feature allows the FakeThrottle to behave differently from
// the original throttle in order to make the desync detection more reliable.
#ifndef X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION
#define X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION 0
@@ -49,6 +49,15 @@
#endif
+inline void SetUInt(uint32_t b, uint8_t index, uint8_t size, uint8_t value) {
+ for (uint8_t i = 0; i> i) & 1);
+}
+
+inline void SetBit(uint32_t b, uint8_t index, bool value) {
+ bitWrite(b, index, value);
+}
+
namespace x52 {
namespace pro {
@@ -104,6 +113,7 @@ struct JoystickState {
typedef BitField Binary;
void SetFromBinary(const Binary&);
+ void SetFromBinary2(const uint64_t);
void ToBinary(Binary&) const;
};
@@ -142,6 +152,7 @@ struct JoystickConfig {
typedef BitField Binary;
void SetFromBinary(const Binary&);
+ void SetFromBinary2(const uint64_t);
void ToBinary(Binary&) const;
};
@@ -281,8 +292,7 @@ inline void JoystickState::ToBinary(Binary& b) const {
b.SetBit(55, button_t6);
}
-
-// JoystickClient makes it possible to use some of your Arduino pins as a
+// FakeThrottle makes it possible to use some of your Arduino pins as a
// connection to the PS/2 socket of an X52 Pro Joystick.
//
// These pin names (C01..C04) were printed on the PCB of my X52 joystick.
@@ -303,11 +313,11 @@ inline void JoystickState::ToBinary(Binary& b) const {
// My X52 Pro throttle uses 4.1-4.2V for both power and GPIO but the joystick
// works with 3.3V too.
template
-class JoystickClient {
+class FakeThrottle {
public:
// Call Setup from the setup function of your Arduino project to initialize
- // a JoystickClient instance.
- void Setup() {
+ // a FakeThrottle instance.
+ void setup() {
pinMode(PIN_C01, OUTPUT_12MA);
pinMode(PIN_C02, OUTPUT_12MA);
// On the teensy the digitalWrite seems to work only after pinMode.
@@ -337,6 +347,17 @@ class JoystickClient {
JoystickConfig::Binary send_buf;
cfg.ToBinary(send_buf);
+ uint32_t sendbuf=0;
+ uint64_t recvbuf = 0;
+ SetUInt(sendbuf, 0, 5, cfg.led_brightness);
+ SetBit(sendbuf, 5, cfg.pov_1_led_blinking);
+ SetUInt(sendbuf, 6, 2, cfg.button_a_led);
+ SetUInt(sendbuf, 8, 2, cfg.pov_2_led);
+ SetBit(sendbuf, 10, !cfg.button_fire_led);
+ SetUInt(sendbuf, 11, 2, cfg.button_b_led);
+ SetUInt(sendbuf, 13, 2, cfg.button_t1_t2_led);
+ SetUInt(sendbuf, 15, 2, cfg.button_t3_t4_led);
+ SetUInt(sendbuf, 17, 2, cfg.button_t5_t6_led);
// deadline for the whole frame transmission
unsigned long deadline = micros() + wait_micros;
@@ -350,6 +371,7 @@ class JoystickClient {
#endif
if (i >= 57)
digitalWrite(PIN_C01, send_buf.Bit(i-57));
+ //digitalWrite(PIN_C01, bitRead(sendbuf,i-57));
digitalWrite(PIN_C02, HIGH);
@@ -360,7 +382,7 @@ class JoystickClient {
X52DebugPrint("Error waiting for C04=1. Clock cycle: ");
X52DebugPrintln(i);
#if X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION
- if (i >= 57)
+ if (i >= 57)
digitalWrite(PIN_C01, HIGH);
#endif
digitalWrite(PIN_C02, LOW);
@@ -404,9 +426,11 @@ class JoystickClient {
// falling edge of C04 and the rising edge of C02.
if (i < JoystickState::NUM_BITS)
recv_buf.SetBit(i, bool(digitalRead(PIN_C03)));
+ //bitWrite(recvbuf, i, bool(digitalRead(PIN_C03)));
}
state.SetFromBinary(recv_buf);
+ //state.SetFromBinary2(recvbuf);
return 0;
}
@@ -416,16 +440,16 @@ class JoystickClient {
};
-// ThrottleClient makes it possible to use some of your Arduino pins as a
+// FakeJoystick makes it possible to use some of your Arduino pins as a
// connection to the PS/2 socket of an X52 Pro Throttle.
//
-// The pin config is the same as that of the JoystickClient.
+// The pin config is the same as that of the FakeThrottle.
template
-class ThrottleClient {
+class FakeJoystick {
public:
// Call Setup from the setup function of your Arduino project to initialize
- // a ThrottleClient instance.
- void Setup() {
+ // a FakeJoystick instance.
+ void setup() {
pinMode(PIN_C01, INPUT);
pinMode(PIN_C02, INPUT);
pinMode(PIN_C03, OUTPUT);
diff --git a/lib/X52-HOTAS/src/x52_std.h b/lib/X52-HOTAS/src/x52_std.h
index 568182b..3acf7a1 100644
--- a/lib/X52-HOTAS/src/x52_std.h
+++ b/lib/X52-HOTAS/src/x52_std.h
@@ -344,7 +344,7 @@ template
volatile int InterruptPulseWaiter::m_Counter = 0;
-// JoystickClient makes it possible to use some of your Arduino pins as a
+// FakeThrottle makes it possible to use some of your Arduino pins as a
// connection to the PS/2 socket of an X52 (non-Pro) Joystick.
//
// These pin names (C01..C04) were printed on the PCB of my X52 joystick.
@@ -364,10 +364,10 @@ volatile int InterruptPulseWaiter::m_Counter = 0;
//
// My joystick claims to be 5V 500mW but works with 3.3V too.
template >
-class JoystickClient {
+class FakeThrottle {
public:
// Call Setup from the setup function of your Arduino project to initialize
- // a JoystickClient instance.
+ // a FakeThrottle instance.
void Setup() {
pinMode(PIN_C01, OUTPUT);
// The value of C01 is allowed to be anything between frames (undefined).
@@ -490,15 +490,15 @@ class JoystickClient {
};
-// ThrottleClient makes it possible to use some of your Arduino pins as a
+// FakeJoystick makes it possible to use some of your Arduino pins as a
// connection to the PS/2 socket of an X52 (non-Pro) Throttle.
//
-// The pin config is the same as that of the JoystickClient.
+// The pin config is the same as that of the FakeThrottle.
template
-class ThrottleClient {
+class FakeJoystick {
public:
// Call Setup from the setup function of your Arduino project to initialize
- // a ThrottleClient instance.
+ // a FakeJoystick instance.
void Setup() {
pinMode(PIN_C01, INPUT);
pinMode(PIN_C02, INPUT);
diff --git a/patch-SDFS.py b/scripts/patch-SDFS.py
similarity index 100%
rename from patch-SDFS.py
rename to scripts/patch-SDFS.py
diff --git a/scripts/picoasm.py b/scripts/picoasm.py
new file mode 100644
index 0000000..b8924d8
--- /dev/null
+++ b/scripts/picoasm.py
@@ -0,0 +1,30 @@
+"""
+Custom pioasm compiler script for platformio.
+(c) 2022 by P.Z.
+
+"""
+from os.path import join
+import glob
+import sys
+Import("env")
+
+platform = env.PioPlatform()
+PROJ_SRC = env["PROJECT_SRC_DIR"]
+PIO_FILES = glob.glob(join(PROJ_SRC, '*.pio'), recursive=True)
+
+if PIO_FILES:
+ print("==============================================")
+ print('PIO ASSEMBLY COMPILER')
+ try:
+ PIOASM_DIR = platform.get_package_dir("tool-pioasm-rp2040-earlephilhower")
+ except:
+ print("tool-pioasm-rp2040-earlephilhower not found!")
+ print("please install it using the following command:")
+ print("pio pkg install -g --tool \"earlephilhower/tool-pioasm-rp2040-earlephilhower@^5.100300.220714\"")
+ sys.exit()
+
+ PIOASM_EXE = join(PIOASM_DIR, "pioasm")
+ print("pio files found:")
+ for filename in PIO_FILES:
+ env.Execute(PIOASM_EXE + f' -o c-sdk {filename} {filename}.h')
+ print("==============================================")
\ No newline at end of file
diff --git a/src/i2c_node.cpp b/src/i2c_node.cpp
index 147a049..1070aea 100644
--- a/src/i2c_node.cpp
+++ b/src/i2c_node.cpp
@@ -4,280 +4,377 @@
#include
#include "CRC.h"
#include "Wire.h"
+#include
-//int i2cADDR = calcCRC8((uint8_t*)rp2040.getChipID(), sizeof(rp2040.getChipID()));
-int i2cADDR = 0x21;
// Buttons
// D E I HAT HAT HAT HAT Scroll Scroll RB LB
// Axis
// ????
#define I2C_SDA 0
#define I2C_SCL 1
-#define BUTTON1 2
-#define BUTTON2 3
-#define BUTTON3 4
-#define HAT1_1 5
-#define HAT1_2 6
-#define HAT1_3 7
-#define HAT1_4 8
-#define SCROLL_1 9
-#define SCROLL_2 10
-#define LMB 12
-#define RMB 11
-#define MUX_SIG A2
-#define MUX_S4 A1
-#define MUX_S3 A0
-#define MUX_S2 22
-#define MUX_S1 21
-#define MUX_EN 20
#define WS2812_PIN NULL
#define EXT_NUM_PIXELS 3
+uint8_t maxHats = 8;
+uint8_t maxAxis = 32;
+uint8_t maxButtons = 32;
+uint8_t maxMuxes = 5;
-
-//Adafruit_NeoPixel ext_pixel(EXT_NUM_PIXELS, WS2812_PIN);
-
-uint8_t ADCresolution = 11;
+//int i2cADDR = calcCRC8((uint8_t*)rp2040.getChipID(), sizeof(rp2040.getChipID()));
+struct _config {
+ int i2cADDR = 0x21;
+ uint8_t ADCResolution = 11;
+ uint8_t currentADCResolution;
+ uint8_t digitalPinCount = 16;
+ uint8_t analogPinCount = 1;
+ uint8_t muxCount = 1;
+ uint8_t axisCount = 3;
+ uint8_t buttonCount = 7;
+ uint8_t hatCount = 1;
+ // pin ids used for reading
+ uint8_t digitalPins[32];
+ uint8_t analogPins[32];
+ // pin modes (INPUT, OUTPUT, INPUT_PULLUP, INPUT_PULLDOWN, OUTPUT_2MA, OUTPUT_4MA, OUTPUT_8MA, OUTPUT_12MA)
+ uint8_t digitalModePins[32];
+ uint8_t analogModePins[32];
+
+ uint8_t buttonPins[32];
+ uint8_t bInverted[32];
+ uint8_t axisPins[32];
+ uint8_t aInverted[32];
+ // order is: N,E,S,W
+ uint8_t hatPins[8][4];
+ // order is: EN,S0,S1,S2,S3,SIG
+ uint8_t muxPins[5][6];
+};
+_config config;
+Adafruit_NeoPixel ext_pixel(EXT_NUM_PIXELS, WS2812_PIN);
volatile RGBW led;
+
uint8_t i2cDataSize = 0;
-struct __attribute__((packed, aligned(1))) Command{
- uint16_t command_type;
- uint16_t id;
-}command;
uint8_t i2cDataBuf[64];
-void receive(int len);
-void request();
-uint16_t readMuxChannel(uint8_t channel);
-
-
-///////////////////////////////////////////////
-// primary core used for noce specific tasks //
-///////////////////////////////////////////////
-
-////////////////////////////////////////////
-// secondary core used for communications //
-////////////////////////////////////////////
-
-void setup() {
-
-#if defined(ARDUINO_RASPBERRY_PI_PICO)||defined(ARDUINO_RASPBERRY_PI_PICO_W) // This changes the SMPS to be less efficient but also less noisy
- pinMode(23, OUTPUT);
- digitalWrite(23, HIGH);
-#endif
-
- //ext_pixel.begin();
-
- analogReadResolution(ADCresolution);
-
- pinMode(BUTTON1, OUTPUT_2MA);
- pinMode(BUTTON2, OUTPUT_2MA);
- pinMode(BUTTON3, OUTPUT_2MA);
-
- pinMode(HAT1_1, OUTPUT_2MA);
- pinMode(HAT1_2, OUTPUT_2MA);
- pinMode(HAT1_3, OUTPUT_2MA);
- pinMode(HAT1_4, OUTPUT_2MA);
- pinMode(SCROLL_1, OUTPUT_2MA);
- pinMode(SCROLL_2, OUTPUT_2MA);
- pinMode(LMB, OUTPUT_2MA);
- pinMode(RMB, OUTPUT_2MA);
- pinMode(MUX_EN, OUTPUT_2MA);
- pinMode(MUX_S1, OUTPUT_2MA);
- pinMode(MUX_S2, OUTPUT_2MA);
- pinMode(MUX_S3, OUTPUT_2MA);
- pinMode(MUX_S4, OUTPUT_2MA);
- pinMode(MUX_SIG, INPUT);
-
- digitalWrite(BUTTON1, HIGH);
- digitalWrite(BUTTON2, HIGH);
- digitalWrite(BUTTON3, HIGH);
- digitalWrite(HAT1_1, HIGH);
- digitalWrite(HAT1_2, HIGH);
- digitalWrite(HAT1_3, HIGH);
- digitalWrite(HAT1_4, HIGH);
- digitalWrite(SCROLL_1, HIGH);
- digitalWrite(SCROLL_2, HIGH);
- digitalWrite(LMB, HIGH);
- digitalWrite(RMB, HIGH);
- digitalWrite(MUX_EN, HIGH);
- digitalWrite(MUX_S1, LOW);
- digitalWrite(MUX_S2, LOW);
- digitalWrite(MUX_S3, LOW);
- digitalWrite(MUX_S4, LOW);
-
+void readEEPROM() {
+ //EEPROM.get(0,config);
+ for (uint8_t i = 0; i T readMuxChannel(uint8_t channel) {
- digitalWrite(MUX_S1, ((channel >> 0) & 0x01));
- digitalWrite(MUX_S2, ((channel >> 1) & 0x01));
- digitalWrite(MUX_S3, ((channel >> 2) & 0x01));
- digitalWrite(MUX_S4, ((channel >> 3) & 0x01));
- digitalWrite(MUX_EN, LOW);
- delay(1);
- T value = analogRead(MUX_SIG);
- digitalWrite(MUX_EN, HIGH);
+// Reads the analog pin
+// muxId is 0 its reading a analog pin directly
+// otherwise muxId is used to get the pins from the array for that mux
+// and channel is used to select the pin instead
+template T readAxis(uint8_t muxId, uint8_t channel) {
+ T value = 0;
+ if(muxId>0 && muxId <= config.muxCount) {
+ digitalWrite(config.muxPins[muxId][1], ((channel >> 0) & 0x01));
+ digitalWrite(config.muxPins[muxId][2], ((channel >> 1) & 0x01));
+ digitalWrite(config.muxPins[muxId][3], ((channel >> 2) & 0x01));
+ digitalWrite(config.muxPins[muxId][4], ((channel >> 3) & 0x01));
+ digitalWrite(config.muxPins[muxId][0], LOW);
+ value = analogRead(config.muxPins[muxId][5]);
+ digitalWrite(config.muxPins[muxId][0], HIGH);
+// digitalWrite(MUX_S1, ((channel >> 0) & 0x01));
+// digitalWrite(MUX_S2, ((channel >> 1) & 0x01));
+// digitalWrite(MUX_S3, ((channel >> 2) & 0x01));
+// digitalWrite(MUX_S4, ((channel >> 3) & 0x01));
+// digitalWrite(MUX_EN, LOW);
+// delay(1);
+// value = analogRead(MUX_SIG);
+// digitalWrite(MUX_EN, HIGH);
+ } else {
+ value = analogRead(channel);
+ }
return (T)value;
}
-uint8_t readButton(uint8_t button) {
+bool readButton(uint8_t muxId, uint8_t button) {
+// This is since we default our pins high... we pull low when pressed. (this is oposite to how default true/fasle is)
bool isPressed = 0;
- switch (button) {
- case Button1:
- { isPressed = digitalRead(BUTTON1); break; }
- case Button2:
- { isPressed = digitalRead(BUTTON2); break; }
- case Button3:
- { isPressed = digitalRead(BUTTON3); break; }
- case Button4:
- { isPressed = digitalRead(HAT1_1); break; }
- case Button5:
- { isPressed = digitalRead(HAT1_2); break; }
- case Button6:
- { isPressed = digitalRead(HAT1_3); break; }
- case Button7:
- { isPressed = digitalRead(HAT1_4); break; }
- case Button8:
- { isPressed = digitalRead(SCROLL_1); break; }
- case Button9:
- { isPressed = digitalRead(SCROLL_2); break; }
- case Button10:
- { isPressed = digitalRead(LMB); break; }
- case Button11:
- { isPressed = digitalRead(RMB); break; }
- case Button12:
- { break; }
- case Button13:
- { break; }
- case Button14:
- { break; }
- case Button15:
- { break; }
- case Button16:
- { break; }
- case Button17:
- { break; }
- case Button18:
- { break; }
- case Button19:
- { break; }
- case Button20:
- { break; }
- case Button21:
- { break; }
- case Button22:
- { break; }
- case Button23:
- { break; }
- case Button24:
- { break; }
- case Button25:
- { break; }
- case Button26:
- { break; }
- default: break;
+ if(muxId>0 && muxId <= config.muxCount) {
+ digitalWrite(config.muxPins[muxId][1], ((button >> 0) & 0x01));
+ digitalWrite(config.muxPins[muxId][2], ((button >> 1) & 0x01));
+ digitalWrite(config.muxPins[muxId][3], ((button >> 2) & 0x01));
+ digitalWrite(config.muxPins[muxId][4], ((button >> 3) & 0x01));
+ digitalWrite(config.muxPins[muxId][0], LOW);
+ isPressed = !digitalRead(config.muxPins[muxId][5]);
+ digitalWrite(config.muxPins[muxId][0], HIGH);
+ }
+ else {
+ isPressed = !digitalRead(config.digitalPins[button]);
}
- // This is since we default our pins high... we pull low when pressed. (this is oposite to how default true/fasle is)
- return !isPressed;
+ return isPressed;
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receive(int len) {
- uint16_t command = Wire.read();
- uint16_t id = Wire.read();
-
+ uint8_t command = Wire.read();
switch (command) {
case SetLed: {
-
- //led.raw = (uint32_t)command->data;
- //ext_pixel.setPixelColor(command->id, led.R, led.G, led.B);
- break;
- }
- case SetConfig: {
-
- }
- case GetConfig: {
+ //uint8_t id = Wire.read();
+ led.raw = Wire.read()|(Wire.read()<<8)|(Wire.read()<<16)|(Wire.read()<<24);
+ //ext_pixel.setPixelColor(id, led.R, led.G, led.B);
break;
}
case GetLed: {
- //((uint32_t*)command.buf)[0] = ext_pixel.getPixelColor(command->id);
+ //uint8_t id = Wire.read();
+ //((uint32_t*)i2cDataBuf)[0] = ext_pixel.getPixelColor(id);
//i2cBuffUsed += sizeof(uint32_t);
break;
}
case GetAxis: {
- //a = readMuxChannel(command->id);
- //command->data = (uint16_t*)a;
-
- //((uint16_t*)i2cDataBuf)[0] = readMuxChannel(id);
- ((uint16_t*)i2cDataBuf)[0] = readMuxChannel(id);
- //((uint16_t*)i2cDataBuf)[0] = readMuxChannel(id,uin);
+ uint8_t id = Wire.read();
+ uint8_t muxId = 0;
+ if (Wire.available())
+ muxId = Wire.read();
+ ((uint16_t*)i2cDataBuf)[0] = readAxis(muxId, id);
i2cDataSize = sizeof(uint16_t);
break;
}
case GetButton: {
- i2cDataBuf[0] = readButton(id);
+ uint8_t id = Wire.read();
+ uint8_t muxId = 0;
+ if (Wire.available())
+ muxId = Wire.read();
+ i2cDataBuf[0] = readButton(muxId, id);
i2cDataSize = sizeof(uint8_t);
-
- //Serial.print("COMMAND TYPE: ");
- //Serial.print(command->command_type);
- //Serial.print(" GetButton ID: ");
- //Serial.print(command->id);
- //Serial.print(" STATE: ");
- //Serial.println((bool)command->data);
- //Serial.print("BUFF: ");
- //for (int i = 0; i < i2cBuffUsed; i++) {
- // Serial.print(((uint8_t*)i2cBuff)[i], BIN);
- //}
- //Serial.println();
-
break;
}
+ case Config: {
+ uint16_t configCommand = Wire.read()|(Wire.read()<<8);
+ switch (configCommand) {
+ case ConfigUpdate: {
+ break;
+ }
+ case SetI2cId: {
+ uint8_t id = Wire.read();
+ if (config.i2cADDR != id) {
+ config.i2cADDR = id;
+ }
+ break;
+ }
+ case GetI2cId: {
+ i2cDataBuf[0] = config.i2cADDR;
+ i2cDataSize = 1;
+ break;
+ }
+ case SetAnalogResolution: {
+ config.ADCResolution = Wire.read();
+ if (config.currentADCResolution != config.ADCResolution) {
+ analogReadResolution(config.ADCResolution);
+ config.currentADCResolution = config.ADCResolution;
+ }
+ break;
+ }
+ case SetButtonPin: {
+ uint8_t id = Wire.read();
+ uint8_t pin = Wire.read();
+ if (id < maxButtons)
+ config.digitalPins[id] = pin;
+ break;
+ }
+ case GetButtonPin: {
+ uint8_t id = Wire.read();
+ i2cDataBuf[0] = config.digitalPins[id];
+ i2cDataSize = sizeof(uint8_t);
+ break;
+ }
+ case SetAxisPin: {
+ uint8_t id = Wire.read();
+ uint8_t pin = Wire.read();
+ if (id < maxAxis)
+ config.analogPins[id] = pin;
+ break;
+ }
+ case GetAxisPin: {
+ uint8_t id = Wire.read();
+ i2cDataBuf[0] = config.analogPins[id];
+ i2cDataSize = sizeof(uint8_t);
+ break;
+ }
+ case SetHatPins: {
+ uint8_t id = Wire.read();
+ if (id < maxHats)
+ for (uint8_t i = 0; i< 4; i++) {
+ config.hatPins[id][i] = Wire.read();
+ }
+ break;
+ }
+ case GetHatPins: {
+ uint8_t id = Wire.read();
+ if (id < maxHats) {
+ memcpy(i2cDataBuf, config.hatPins[id], sizeof(config.hatPins[id]));
+ i2cDataSize = sizeof(config.hatPins[id]);
+ }
+ break;
+ }
+ case SetMuxPins: {
+ uint8_t id = Wire.read();
+ if (id < maxMuxes)
+ for (uint8_t i = 0; i< 6; i++) {
+ config.muxPins[id][i] = Wire.read();
+ }
+ break;
+ }
+ case GetMuxPins: {
+ uint8_t id = Wire.read();
+ if (id < maxMuxes) {
+ memcpy(i2cDataBuf, config.muxPins[id], sizeof(config.muxPins[id]));
+ i2cDataSize = sizeof(config.muxPins[id]);
+ }
+ break;
+ }
+ case SetButtonCount: {
+ uint8_t count = Wire.read();
+ if (count < maxButtons)
+ config.buttonCount = count;
+ break;
+ }
+ case GetButtonCount: {
+ i2cDataBuf[0] = config.buttonCount;
+ i2cDataSize = 1;
+ break;
+ }
+ case SetHatCount: {
+ uint8_t count = Wire.read();
+ if (count < maxHats)
+ config.hatCount = count;
+ break;
+ }
+ case GetHatCount: {
+ i2cDataBuf[0] = config.hatCount;
+ i2cDataSize = 1;
+ break;
+ }
+ case SetAxisCount: {
+ uint8_t count = Wire.read();
+ if (count < maxAxis)
+ config.axisCount = count;
+ break;
+ }
+ case GetAxisCount: {
+ i2cDataBuf[0] = config.axisCount;
+ i2cDataSize = 1;
+ break;
+ }
+ case SetMuxCount: {
+ uint8_t count = Wire.read();
+ if (count < maxMuxes)
+ config.muxCount = count;
+ break;
+ }
+ case GetMuxCount: {
+ i2cDataBuf[0] = config.muxCount;
+ i2cDataSize = 1;
+ break;
+ }
+ case GetAnalogResolution: {
+ i2cDataBuf[0] = config.currentADCResolution;
+ i2cDataSize = sizeof(uint8_t);
+ break;
+ }
+ default:
+ break;
+ }
+ }
default:
break;
}
-
}
// function that executes whenever data is received from master
// Called when the I2C slave is read from
void request() {
-
Wire.write(i2cDataBuf, i2cDataSize);
}
-void setup1() {
+void setup() {
+
+// This changes the SMPS to be less efficient but also less noisy
+#if defined(ARDUINO_RASPBERRY_PI_PICO)||defined(ARDUINO_RASPBERRY_PI_PICO_W)
+ pinMode(23, OUTPUT);
+ digitalWrite(23, HIGH);
+#endif
+ // since its not actually a eeprom we MUST only write to it when we REALLY have to
+ EEPROM.begin(512);
+ ////////////////////////////
+ // EEPROM layout: //
+ ////////////////////////////
+ // (1) i2c address //
+ // (1) adc resolution //
+ // (1) digital pin count //
+ // (1) analog pin count //
+ // (1) mux count //
+ // (1) rgb led count //
+ // (1) rgb led pin //
+ // (32) digital pins //
+ // (32) analog pins //
+ // (32) mux pins //
+ ////////////////////////////
+
+ auto a = sizeof(config);
+
+ uint8_t digitalPins[] = {2,3,4,5,6,7,8,9,10,11,12,20,21,22,26,27};
+ uint8_t digitalPinMode[] = {4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4};
+ uint8_t analogPins[] = {28};
+ uint8_t analogPinMode[] = {0};
+ uint8_t buttonPins[] = {2,3,4,5,6,7,8,9,10,11,12,20,21,22,26,27};
+ uint8_t axisPins[] = {28};
+ uint8_t hatPins[8][4] = {{5,6,7,8}};
+ uint8_t muxPins[5][6] = {{20,21,22,26,27,28}};
+
+ memcpy(config.digitalPins, digitalPins, sizeof(digitalPins));
+ memcpy(config.digitalModePins, digitalPinMode, sizeof(digitalPinMode));
+ memcpy(config.analogPins, analogPins, sizeof(analogPins));
+ memcpy(config.analogModePins, analogPinMode, sizeof(analogPinMode));
+ memcpy(config.buttonPins, buttonPins, sizeof(buttonPins));
+ memcpy(config.axisPins, axisPins, sizeof(axisPins));
+ memcpy(config.hatPins, hatPins, sizeof(hatPins));
+ memcpy(config.muxPins, muxPins, sizeof(muxPins));
+
+ //ext_pixel.begin();
- //if (i2cBuff == NULL) {
- // i2cBuff = (uint8_t*)malloc(i2cBuffSize);
- // command = (struct Command*)i2cBuff;
- //}
+ analogReadResolution(config.currentADCResolution);
- pinMode(D0, OUTPUT_2MA);
- pinMode(D1, OUTPUT_2MA);
- digitalWrite(D0, HIGH);
- digitalWrite(D1, HIGH);
+ for (uint8_t i = 0; i
+
+//#include "HID_Report.h"
#include
#include
#include
#include "CRC.h"
#include "Wire.h"
+#include "SPI.h"
+//U8G2_ST7528_ERC16064_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 255, /* dc=*/ 255, /* reset=*/ 255);
// Select the FileSystem by uncommenting one of the lines below
@@ -40,8 +44,10 @@ LittleFSConfig fileSystemConfig = LittleFSConfig();
#elif defined USE_SDFS
#include
const char* fsName = "SDFS";
+
FS* fileSystem = &SDFS;
SDFSConfig fileSystemConfig = SDFSConfig();
+
// fileSystemConfig.setCSPin(chipSelectPin);
#else
#error Please select a filesystem first by uncommenting one of the "-D USE_xxx" lines in the usb.ini file located in "config" folder.
@@ -50,6 +56,22 @@ SDFSConfig fileSystemConfig = SDFSConfig();
#include "IniConfig.h"
IniConfig ini(&SDFS);
+typedef struct {
+ uint8_t buttons;
+ uint8_t hats;
+ uint8_t axis;
+
+} input_id;
+
+
+typedef union TU_ATTR_PACKED{
+ struct {
+ uint8_t type:2;
+ uint8_t id:6;
+ };
+ uint8_t option;
+}input_type;
+
bool LED_on;
bool LED_breathe;
uint8_t LED_brightness;
@@ -61,29 +83,25 @@ int report = 1;
/*== LED ==*/
Adafruit_NeoPixel pixel;
-bool enableKeyboard = 0;
-bool enableMouse = 0;
-uint8_t DeviceCount;
+input_id inputs_id[MAX_REPORT_ID];
+
+bool enableKeyboard = 1;
+bool enableMouse = 1;
+bool enableMsc = 1;
+uint8_t IdCount;
+uint8_t MaxDeviceCount = MAX_REPORT_ID;
uint16_t hue;
uint32_t nextScan = millis();
uint32_t nextScanPrint = millis();
uint usb_report_size;
uint8_t usb_report[MAX_HID_DESCRIPTOR_SIZE];
-typedef struct {
- uint8_t buttons;
- uint8_t hats;
- uint8_t axis;
-
-} input_id;
-input_id inputs_id[MAX_REPORT_ID];
-
uint16_t axis_start[MAX_REPORT_ID];
uint16_t button_start[MAX_REPORT_ID];
uint16_t hat_start[MAX_REPORT_ID];
uint16_t total_bits[MAX_REPORT_ID];
-uint16_t largest_bits;
+//uint16_t largest_bits;
volatile uint8_t reports[MAX_REPORT_ID][64];
uint8_t old_reports[MAX_REPORT_ID][64];
@@ -105,14 +123,18 @@ uint16_t HatCount = 1;
uint8_t hid_usage_page_val = HID_USAGE_PAGE_DESKTOP;
uint8_t hid_usage_val = HID_USAGE_DESKTOP_JOYSTICK;
-Adafruit_USBD_HID hid_joystick;
-Adafruit_USBD_HID hid_kbm;
+uint8_t usedIds[128];
+uint8_t slaveCount;
-byte i2cIDs[128];
+Adafruit_USBD_HID usb_hid;
+//Adafruit_USBD_HID hid_kbm;
+Adafruit_USBD_MSC usb_msc;
+byte i2cIDs[128];
-void setupUSB(bool begin);
+void setupDescripor();
+void setUSB(bool);
static bool fsOK;
#ifdef ARDUINO_RASPBERRY_PI_PICO_W //todo add more wifi boards (eg esp32)
#include "webInterface.h"
@@ -150,14 +172,34 @@ uint32_t rainbow(uint16_t _hue, uint8_t saturation, uint8_t brightness, bool gam
// this is here since the joystick still works and doesnt need to be replaced (it will be gutted after throttle is properly done)
-
+//#define USE_NEW
+//#define USE_STD
#define X52_BUSY_WAIT 0
-#define X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION 0
-#include
+#define X52_PRO_IMPROVED_JOYSTICK_CLIENT_DESYNC_DETECTION 1
+#ifndef USE_NEW
+#include "x52_pro.h"
+#include "x52_util.h"
+#else
+#ifdef USE_STD
+//#include "new_x52_std.h"
+//#include "new_x52_util.h"
+#else
+#include "new_x52_pro.h"
+#include "new_x52_util.h"
+#endif
+#endif
#define MAX_UPDATES_PER_SECOND 300
// TODO: Choose your favorite digital pins on your board.
-x52::pro::JoystickClient joystick_client;
+#ifndef USE_NEW
+x52::pro::FakeThrottle fakeThrottle;
+#else
+#ifdef USE_STD
+FakeStdThrottle fakeThrottle(pio0, D20, D26, D21, D22);
+#else
+FakeProThrottle fakeThrottle(pio0, D20, D26, D21, D22);
+#endif
+#endif
//x52::pro::JoystickConfig cfg;
//x52::pro::JoystickState state;
@@ -172,6 +214,7 @@ x52::pro::JoystickClient joystick_client;
// Return zero will cause the stack to STALL request
uint16_t get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
+ memset(buffer,0,reqlen);
Serial.print("get_report type: ");
Serial.println((int)report_type);
Serial.print("get_report id: ");
@@ -183,7 +226,16 @@ uint16_t get_report_callback (uint8_t report_id, hid_report_type_t report_type,
break;
case (hid_report_type_t)HID_REPORT_TYPE_INPUT:
- case (hid_report_type_t)HID_REPORT_TYPE_FEATURE:
+ case (hid_report_type_t)HID_REPORT_TYPE_FEATURE:
+ if (report_id < 1) {
+ buffer[0] = IdCount;
+ } else if (report_id > 0 && report_id <= MAX_REPORT_ID) {
+ buffer[0] = inputs_id[report_id].buttons;
+ buffer[1] = inputs_id[report_id].hats;
+ buffer[2] = inputs_id[report_id].axis;
+ buffer[3] = AxisResolution;
+ } else {break;}
+
return reqlen;
}
return 0;
@@ -206,11 +258,62 @@ void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8
break;
case HID_REPORT_TYPE_FEATURE:
+
break;
}
}
+//--------------------------------------------------------------------+
+// SD Card
+//--------------------------------------------------------------------+
+
+int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+ (void) bufsize;
+ bool rc=false;
+#if SD_FAT_VERSION >= 20000
+// rc = sd->card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
+#else
+ rc = sd->card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512);
+#endif
+
+ return rc ? bufsize : -1;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and
+// return number of written bytes (must be multiple of block size)
+int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+ bool rc=false;
+
+#if SD_FAT_VERSION >= 20000
+// rc = sd->card()->writeSectors(lba, buffer, bufsize/512);
+#else
+ rc = sd->card()->writeBlocks(lba, buffer, bufsize/512);
+#endif
+
+ return rc ? bufsize : -1;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void msc_flush_cb (void)
+{
+#if SD_FAT_VERSION >= 20000
+// sd->card()->syncDevice();
+#else
+ sd->card()->syncBlocks();
+#endif
+
+ // clear file system's cache to force refresh
+ //sd->cacheClear();
+
+// sd_changed = true;
+}
+
+
bool getButtonI2cSlave (int slaveID, int inputID) {
Wire.beginTransmission(slaveID);
Wire.write(GetButton);
@@ -327,6 +430,7 @@ void writeSystemINI() {
ini.write( "hid report", "DeviceName", DeviceName.c_str());
ini.writeBool("hid report", "enableMouse", enableMouse);
ini.writeBool("hid report", "enableKeyboard", enableKeyboard);
+ ini.writeBool("hid report", "enableMsc", enableMsc);
ini.writeInt( "hid report", "UsagePage", hid_usage_page_val);
ini.writeInt( "hid report", "Usage", hid_usage_val);
ini.writeInt( "hid report", "ButtonCount", ButtonCount);
@@ -338,11 +442,12 @@ void writeSystemINI() {
void readSystemINI() {
ini.open("/config/settings.ini");
- DeviceName = ini.read("hid report", "DeviceName");
+ DeviceName = ini.read("hid report", "DeviceName");
hid_usage_page_val = ini.readInt( "hid report", "UsagePage");
hid_usage_val = ini.readInt( "hid report", "Usage");
enableMouse = ini.readBool("hid report", "enableMouse");
enableKeyboard = ini.readBool("hid report", "enableKeyboard");
+ enableMsc = ini.readBool("hid report", "enableMsc");
ButtonCount = ini.readInt( "hid report", "ButtonCount");
HatCount = ini.readInt( "hid report", "HatCount");
AxisCount = ini.readInt( "hid report", "AxisCount");
@@ -350,29 +455,57 @@ void readSystemINI() {
ADCResolution = ini.readInt( "hid report", "ADCResolution");
}
+void setupSD() {
+ ////////////////////////////////
+ // FILESYSTEM INIT
+ fileSystemConfig.setCSPin(17);
+ fileSystemConfig.setSPISpeed(50*MHZ);
+ fileSystemConfig.setAutoFormat(false);
+ fileSystem->setConfig(fileSystemConfig);
+ fsOK = fileSystem->begin();
+ //DBG_OUTPUT_PORT.println(fsOK ? F("Filesystem initialized.") : F("Filesystem init failed!"));
+}
+
+void setupMSC () {
+ usb_msc.setMaxLun(1);
+ FSInfo64 fs_info;
+ fileSystem->info64(fs_info);
+ usb_msc.setID("test1", "test2", "0.0");
+ usb_msc.setCapacity(fs_info.totalBytes/fs_info.blockSize, fs_info.blockSize);
+ usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
+ usb_msc.setUnitReady(true);
+}
+
+
void setupINI() {
- if (!fileSystem->exists("/config"))
- fileSystem->mkdir("/config");
if (!fileSystem->exists("/config/settings.ini")) {
File file = fileSystem->open("/config/settings.ini","w");
file.close();
- ini.open("/config/settings.ini");
- ini.write( "hid report", "DeviceName", "RP2040-HID");
- ini.writeBool("hid report", "enableMouse", false);
- ini.writeBool("hid report", "enableKeyboard", false);
- ini.writeInt( "hid report", "UsagePage", HID_USAGE_PAGE_DESKTOP);
- ini.writeInt( "hid report", "Usage", HID_USAGE_DESKTOP_JOYSTICK);
- ini.writeInt( "hid report", "ButtonCount", 64);
- ini.writeInt( "hid report", "HatCount", 1);
- ini.writeInt( "hid report", "AxisCount", 8);
- ini.writeInt( "hid report", "AxisResolution", 11);
- ini.writeInt( "hid report", "ADCResolution", 11);
-
+ DeviceName= "RP2040-HID";
+ enableMouse= false;
+ enableKeyboard=false;
+ hid_usage_page_val= HID_USAGE_PAGE_DESKTOP;
+ hid_usage_val= HID_USAGE_DESKTOP_JOYSTICK;
+ ButtonCount= 64;
+ HatCount= 1;
+ AxisCount= 8;
+ AxisResolution= 11;
+ ADCResolution= 11;
+ writeSystemINI();
+ } else {
+ readSystemINI();
}
- readSystemINI();
}
-void setupUSB(bool begin) {
+void setupDescripor() {
+ uint16_t maxBuffSize = MAX_HID_DESCRIPTOR_SIZE;
+ if (enableMouse)
+ maxBuffSize -= 79;
+// MaxDeviceCount -= 1;
+ if (enableKeyboard)
+ maxBuffSize -= 67;
+// MaxDeviceCount -= 1;
+
// reset the connection
memset(inputs_id, 0, sizeof(inputs_id));
memset(usb_report, 0, sizeof(usb_report));
@@ -381,8 +514,12 @@ void setupUSB(bool begin) {
memset(axis_start,0,sizeof(axis_start));
memset(total_bits,0,sizeof(total_bits));
usb_report_size=0;
- largest_bits=0;
- DeviceCount=0;
+ IdCount=0;
+
+ //this buffer will be cleared and freed at the end since its a temp buffer
+ uint8_t* t_buffer = (uint8_t*)malloc(150);
+ memset(t_buffer,0,150);
+ size_t t_buffer_size;
/*
Calculate how many "devices" we will need to emulate
@@ -393,22 +530,48 @@ void setupUSB(bool begin) {
for (uint16_t i=ButtonCount, j=1; i>0; i-=MIN(device_max_button_count,i), j++) {
inputs_id[j].buttons = i>device_max_button_count ? device_max_button_count:i;
- DeviceCount = j>DeviceCount ? j:DeviceCount;
+ IdCount = j>IdCount ? j:IdCount;
}
for (uint16_t i=HatCount, j=1; i>0; i-=MIN(device_max_hat_count, i), j++) {
inputs_id[j].hats = i>device_max_hat_count ? device_max_hat_count:i;
- DeviceCount = j>DeviceCount ? j:DeviceCount;
+ IdCount = j>IdCount ? j:IdCount;
}
for (uint8_t i=AxisCount, j=1; i>0;i-=MIN(device_max_axis_count,i), j++) {
inputs_id[j].axis = i>device_max_axis_count ? device_max_axis_count:i;
- DeviceCount = j>DeviceCount ? j:DeviceCount;
+ IdCount = j>IdCount ? j:IdCount;
}
- for (uint16_t i = 1; i<=DeviceCount; i++) {
- makeDescriptor(i, AxisResolution, inputs_id[i].axis, inputs_id[i].hats, inputs_id[i].buttons, usb_report, &usb_report_size);
+ for (uint16_t id = 1; id<=IdCount; id++) {
+ t_buffer_size = 0;
+ makeJoystickDescriptor(id, AxisResolution, inputs_id[id].axis, inputs_id[id].hats, inputs_id[id].buttons, t_buffer, &t_buffer_size);
+ if (usb_report_size + t_buffer_size < maxBuffSize) {
+ memmove(usb_report+usb_report_size, t_buffer, t_buffer_size);
+ usb_report_size += t_buffer_size;
+ }
+ memset(t_buffer, 0, 150);
+// makeJoystickDescriptor(id, AxisResolution, inputs_id[id].axis, inputs_id[id].hats, inputs_id[id].buttons, usb_report, &usb_report_size);
}
- for (uint8_t rep = 1; rep < MAX_REPORT_ID; rep++) {
- largest_bits = (largest_bits < total_bits[rep]) ? total_bits[rep] : largest_bits;
+ if (enableKeyboard) {
+ t_buffer_size = 0;
+ makeKeyboardDescriptor(IdCount+1,t_buffer, &t_buffer_size);
+ if (usb_report_size + t_buffer_size < MAX_HID_DESCRIPTOR_SIZE) {
+ memmove(usb_report+usb_report_size,t_buffer,t_buffer_size);
+ usb_report_size += t_buffer_size;
+ memset(t_buffer,0,150);
+ }
}
+ if (enableMouse) {
+ t_buffer_size = 0;
+ makeMouseDescriptor(IdCount+2,t_buffer, &t_buffer_size);
+ if (usb_report_size + t_buffer_size < MAX_HID_DESCRIPTOR_SIZE) {
+ memmove(usb_report+usb_report_size,t_buffer,t_buffer_size);
+ usb_report_size += t_buffer_size;
+ memset(t_buffer,0,150);
+ }
+ }
+ free(t_buffer);
+}
+
+void setUSB(bool begin) {
TinyUSBDevice.detach();
TinyUSBDevice.clearConfiguration();
@@ -422,48 +585,21 @@ void setupUSB(bool begin) {
if (begin)
SerialTinyUSB.begin(115200);
- if (DeviceCount > 0) {
- hid_joystick.setPollInterval(1);
- hid_joystick.setBootProtocol(HID_ITF_PROTOCOL_NONE);
- hid_joystick.setReportDescriptor(usb_report, usb_report_size);
- hid_joystick.setReportCallback(get_report_callback, set_report_callback);
- if (hid_joystick.isValid())
- TinyUSBDevice.addInterface(hid_joystick);
+ if (IdCount > 0) {
+ // char name;
+ // name = DeviceName.concat("Mouse/Keyboard");
+ usb_hid.setPollInterval(1);
+ usb_hid.setBootProtocol(HID_ITF_PROTOCOL_NONE);
+ usb_hid.setReportDescriptor(usb_report, usb_report_size);
+ usb_hid.setReportCallback(get_report_callback, set_report_callback);
+ /// usb_hid.setStringDescriptor(&name);
+ if (usb_hid.isValid())
+ TinyUSBDevice.addInterface(usb_hid);
else
- hid_joystick.begin();
+ usb_hid.begin();
}
-
- // HID report descriptor using TinyUSB's template
- if(enableMouse || enableKeyboard) {
- if(enableMouse && enableKeyboard) {
- uint8_t desc_hid_report[] = {
- TUD_HID_REPORT_DESC_KEYBOARD( VA_HID_REPORT_ID(1) ),
- TUD_HID_REPORT_DESC_MOUSE ( VA_HID_REPORT_ID(2) ),
- };
- char name = DeviceName.concat(" Mouse/Keyboard");
- hid_kbm.setStringDescriptor(&name);
- hid_kbm.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
- }
- if (enableMouse && !enableKeyboard) {
- uint8_t desc_hid_report[] = {
- TUD_HID_REPORT_DESC_MOUSE ( ),
- };
- char name = DeviceName.concat(" Mouse");
- hid_kbm.setStringDescriptor(&name);
- hid_kbm.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
- }
- if (!enableMouse && enableKeyboard) {
- uint8_t desc_hid_report[] = {
- TUD_HID_REPORT_DESC_KEYBOARD( ),
- };
- char name = DeviceName.concat(" Keyboard");
- hid_kbm.setStringDescriptor(&name);
- hid_kbm.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
- }
- if (hid_kbm.isValid())
- TinyUSBDevice.addInterface(hid_kbm);
- else
- hid_kbm.begin();
+ if (enableMsc) {
+ usb_msc.begin();
}
TinyUSBDevice.attach();
@@ -481,22 +617,16 @@ void setup() {
// - mbed rp2040
TinyUSB_Device_Init(0);
#endif
- fileSystemConfig.setCSPin(17);
-
- ////////////////////////////////
- // FILESYSTEM INIT
- fileSystemConfig.setAutoFormat(false);
- fileSystem->setConfig(fileSystemConfig);
- fsOK = fileSystem->begin();
- //DBG_OUTPUT_PORT.println(fsOK ? F("Filesystem initialized.") : F("Filesystem init failed!"));
+ setupSD();
+ setupMSC();
setupINI();
- setupUSB(true);
-
+ setupDescripor();
+ setUSB(true);
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
setupWifi();
configTime(3 * 3600, 1, "nl.pool.ntp.org", "0.europe.pool.ntp.org");
#endif
-
+//u8g2.begin();
}
@@ -575,12 +705,12 @@ void loop()
//}
if (TinyUSBDevice.ready()) {
if (readyToUpdate[report] ){
- hid_joystick.sendReport(report, (void *)reports[report], total_bits[report]/8);
+ usb_hid.sendReport(report, (void *)reports[report], total_bits[report]/8);
memcpy(old_reports[report],(void *)reports[report],total_bits[report]/8);
readyToUpdate[report] = false;
}
report++;
- if (report >= DeviceCount)
+ if (report >= IdCount)
report = 1;
}
}
@@ -634,10 +764,14 @@ void setup1()
//setLedI2cSlave(1,0x21,0);
//setLedI2cSlave(2,0x21,0);
- joystick_client.Setup();
+ fakeThrottle.setup();
#if MAX_UPDATES_PER_SECOND
+#ifndef USE_NEW
static x52::util::RateLimiter rate_limiter;
+#else
+ static RateLimiter rate_limiter;
+#endif
#endif
}
@@ -702,23 +836,32 @@ void loop1()
// after the delay introduced by the rate limiter.
// Without PrepareForPoll it can take up to 1500ms for the joystick
// to respond to our PollJoystickState call.
- joystick_client.PrepareForPoll();
+ //WfakeThrottle.PrepareForPoll();
#if MAX_UPDATES_PER_SECOND
+#ifndef USE_NEW
static x52::util::RateLimiter rate_limiter;
+#else
+ static RateLimiter rate_limiter;
+#endif
unsigned long d = rate_limiter.MicrosTillNextUpdate();
if (d == 0) {
#endif
// Query the state of the X52 Pro joystick via the PS/2 connection and send it to
// the PC as the state of the USB joystick emulated by the Arduino-compatible board.
+#ifndef USE_NEW
x52::pro::JoystickConfig cfg;
x52::pro::JoystickState state;
+#else
+ JoystickConfig cfg;
+ JoystickState state;
+#endif
cfg.led_brightness = LED;
- auto timeout_micros = joystick_client.PollJoystickState(state, cfg);
+ auto timeout_micros = fakeThrottle.PollJoystickState(state, cfg);
if (timeout_micros) {
//X52DebugPrintln("PollJoystickState failed");
//delayMicroseconds(timeout_micros);
@@ -726,33 +869,55 @@ void loop1()
}
bool empty = false;
-
+#ifndef USE_NEW
bool p2u = bool(state.pov_2 & x52::Up);
bool p2d = bool(state.pov_2 & x52::Down);
bool p2l = bool(state.pov_2 & x52::Left);
bool p2r = bool(state.pov_2 & x52::Right);
-
+#else
+ bool p2u = bool(state.pov_2 & Up);
+ bool p2d = bool(state.pov_2 & Down);
+ bool p2l = bool(state.pov_2 & Left);
+ bool p2r = bool(state.pov_2 & Right);
+#endif
+
bool M1 = 0;
bool M2 = 0;
bool M3 = 0;
switch (state.mode) {
- case x52::ModeUndefined:
+#ifndef USE_NEW
+ case x52::ModeUndefined:
+#else
+ case ModeUndefined:
+#endif
M1 = 0;
M2 = 0;
M3 = 0;
break;
- case x52::Mode1:
+#ifndef USE_NEW
+ case x52::Mode1:
+#else
+ case Mode1:
+#endif
M1 = 1;
M2 = 0;
M3 = 0;
break;
+#ifndef USE_NEW
case x52::Mode2:
+#else
+ case Mode2:
+#endif
M1 = 0;
M2 = 1;
M3 = 0;
break;
+#ifndef USE_NEW
case x52::Mode3:
+#else
+ case Mode3:
+#endif
M1 = 0;
M2 = 0;
M3 = 1;
@@ -769,7 +934,8 @@ switch (state.mode) {
//Serial.println(getAxisI2cSlave(0x21, 5),BIN);
if (readyToUpdate[1]== false) {
- memset((void *)reports[1], 0, largest_bits/8);
+ //memset((void *)reports[1], 0, largest_bits/8);
+ memset((void *)reports[1], 0, sizeof(reports[1]));
switch (state.pov_1) {
case 0b0001: set_hat(reports[1], 1, 0 ,0b0011); break;
case 0b0011: set_hat(reports[1], 1, 0 ,0b0100); break;
@@ -793,8 +959,8 @@ if (readyToUpdate[1]== false) {
set_button(reports[1], 1, 3, state.button_b);
set_button(reports[1], 1, 4, state.button_c);
set_button(reports[1], 1, 5, state.pinkie_switch);
- set_button(reports[1], 1, 6, getButtonI2cSlave(0x21, Button1));
- set_button(reports[1], 1, 7, getButtonI2cSlave(0x21, Button3));
+ set_button(reports[1], 1, 6, getButtonI2cSlave(0x21, 0));
+ set_button(reports[1], 1, 7, getButtonI2cSlave(0x21, 2));
set_button(reports[1], 1, 8, state.button_t1);
set_button(reports[1], 1, 9, state.button_t2);
set_button(reports[1], 1, 10, state.button_t3);
@@ -802,25 +968,25 @@ if (readyToUpdate[1]== false) {
set_button(reports[1], 1, 12, state.button_t5);
set_button(reports[1], 1, 13, state.button_t6);
set_button(reports[1], 1, 14, state.trigger_stage_2);
- set_button(reports[1], 1, 15, getButtonI2cSlave(0x21, Button10));
+ set_button(reports[1], 1, 15, getButtonI2cSlave(0x21, 9));
set_button(reports[1], 1, 16, empty); // scroll up
set_button(reports[1], 1, 17, empty); //scroll down
- set_button(reports[1], 1, 18, getButtonI2cSlave(0x21, Button11));
+ set_button(reports[1], 1, 18, getButtonI2cSlave(0x21, 10));
set_button(reports[1], 1, 19, p2u);
set_button(reports[1], 1, 20, p2r);
set_button(reports[1], 1, 21, p2d);
set_button(reports[1], 1, 22, p2l);
- set_button(reports[1], 1, 23, getButtonI2cSlave(0x21, Button7));
- set_button(reports[1], 1, 24, getButtonI2cSlave(0x21, Button6));
- set_button(reports[1], 1, 25, getButtonI2cSlave(0x21, Button5));
- set_button(reports[1], 1, 26, getButtonI2cSlave(0x21, Button4));
+ set_button(reports[1], 1, 23, getButtonI2cSlave(0x21, 6));
+ set_button(reports[1], 1, 24, getButtonI2cSlave(0x21, 5));
+ set_button(reports[1], 1, 25, getButtonI2cSlave(0x21, 4));
+ set_button(reports[1], 1, 26, getButtonI2cSlave(0x21, 3));
set_button(reports[1], 1, 27, M1);
set_button(reports[1], 1, 28, M2);
set_button(reports[1], 1, 29, M3);
- set_button(reports[1], 1, 30, getButtonI2cSlave(0x21, Button2));
+ set_button(reports[1], 1, 30, getButtonI2cSlave(0x21, 1));
- // 15/14 scroll mfd
- // 9/8 pg scroll
+ // pin 15/14 scroll mfd
+ // pin 9/8 pg scroll
set_button(reports[1], 1, 31, !digitalRead(10)); //function