From 604bf2cdbe1b2291511922b6f6d7d8916a546294 Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Sat, 23 Apr 2022 07:27:39 -0400 Subject: [PATCH] Wi-Fi Direct alpha --- .vscode/launch.json | 34 ++ CMakeLists.txt | 5 + default_presets/plugin_presets/1.json | 1 + default_presets/plugin_presets/10.json | 1 + default_presets/plugin_presets/11.json | 1 + default_presets/plugin_presets/12.json | 1 + default_presets/plugin_presets/13.json | 1 + default_presets/plugin_presets/14.json | 1 + default_presets/plugin_presets/15.json | 1 + default_presets/plugin_presets/16.json | 1 + default_presets/plugin_presets/17.json | 1 + default_presets/plugin_presets/18.json | 1 + default_presets/plugin_presets/2.json | 1 + default_presets/plugin_presets/3.json | 1 + default_presets/plugin_presets/4.json | 1 + default_presets/plugin_presets/5.json | 1 + default_presets/plugin_presets/6.json | 1 + default_presets/plugin_presets/7.json | 1 + default_presets/plugin_presets/8.json | 1 + default_presets/plugin_presets/9.json | 1 + default_presets/plugin_presets/index.json | 1 + default_presets/presets/Default+Bank.bank | 1 + default_presets/presets/index.banks | 1 + react/public/var/config.json | 15 +- react/src/AndroidHost.tsx | 48 +++ react/src/App.tsx | 2 +- react/src/AppThemed.tsx | 7 +- react/src/MainPage.tsx | 6 +- react/src/PiPedalModel.tsx | 156 +++++++-- react/src/SettingsDialog.tsx | 141 ++++++-- react/src/TemporaryDrawer.tsx | 4 +- react/src/WifiDirectConfigDialog.tsx | 400 ++++++++++++++++++++++ react/src/WifiDirectConfigSettings.tsx | 67 ++++ src/AvahiService.cpp | 2 +- src/CMakeLists.txt | 57 +-- src/ConfigUtil.cpp | 31 +- src/ConfigUtil.hpp | 3 + src/Ipv6Helpers.hpp | 1 + src/PiPedalModel.cpp | 31 ++ src/PiPedalModel.hpp | 5 + src/PiPedalSocket.cpp | 28 +- src/PluginPreset.hpp | 1 + src/SetWifiConfig.cpp | 83 +---- src/Storage.cpp | 69 ++++ src/Storage.hpp | 8 + src/WifiDirectConfigSettings.cpp | 97 ++++-- src/WifiDirectConfigSettings.hpp | 8 +- src/json.hpp | 1 + src/pch.h | 11 +- src/templates/pipedal_p2pd.conf.template | 8 +- 50 files changed, 1145 insertions(+), 205 deletions(-) create mode 100644 default_presets/plugin_presets/1.json create mode 100644 default_presets/plugin_presets/10.json create mode 100644 default_presets/plugin_presets/11.json create mode 100644 default_presets/plugin_presets/12.json create mode 100644 default_presets/plugin_presets/13.json create mode 100644 default_presets/plugin_presets/14.json create mode 100644 default_presets/plugin_presets/15.json create mode 100644 default_presets/plugin_presets/16.json create mode 100644 default_presets/plugin_presets/17.json create mode 100644 default_presets/plugin_presets/18.json create mode 100644 default_presets/plugin_presets/2.json create mode 100644 default_presets/plugin_presets/3.json create mode 100644 default_presets/plugin_presets/4.json create mode 100644 default_presets/plugin_presets/5.json create mode 100644 default_presets/plugin_presets/6.json create mode 100644 default_presets/plugin_presets/7.json create mode 100644 default_presets/plugin_presets/8.json create mode 100644 default_presets/plugin_presets/9.json create mode 100644 default_presets/plugin_presets/index.json create mode 100644 default_presets/presets/Default+Bank.bank create mode 100644 default_presets/presets/index.banks create mode 100644 react/src/AndroidHost.tsx create mode 100644 react/src/WifiDirectConfigDialog.tsx create mode 100644 react/src/WifiDirectConfigSettings.tsx diff --git a/.vscode/launch.json b/.vscode/launch.json index bbb3ffa..9b4c66a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -37,6 +37,40 @@ } ] }, + + { + "name": "(gdb) pipedald", + "type": "cppdbg", + "request": "launch", + // Resolved by CMake Tools: + "program": "${command:cmake.launchTargetPath}", + "args": [ "/etc/pipedal/config", "/etc/pipedal/react", "-port", "0.0.0.0:8080" ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [ + { + // add the directory where our target was built to the PATHs + // it gets resolved by CMake Tools: + "name": "PATH", + "value": "$PATH:${command:cmake.launchTargetDirectory}" + }, + { + "name": "ASAN_OPTIONS", + "value": "detect_leaks=0" + + } + ], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { "name": "(gdb) pipedaltest Launch", "type": "cppdbg", diff --git a/CMakeLists.txt b/CMakeLists.txt index c518c6d..1f7f76f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,11 @@ install ( DESTINATION /etc/pipedal/config/ ) +install ( + DIRECTORY ${PROJECT_SOURCE_DIR}/default_presets + DESTINATION /etc/pipedal/config +) + install (DIRECTORY ${LV2_SOURCE_DIRECTORY} DESTINATION /usr/lib/lv2 ) diff --git a/default_presets/plugin_presets/1.json b/default_presets/plugin_presets/1.json new file mode 100644 index 0000000..475dd42 --- /dev/null +++ b/default_presets/plugin_presets/1.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZaMaximX2","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"ceil": 0,"rel": 25,"thresh": 0}}],"nextInstanceId": 2} \ No newline at end of file diff --git a/default_presets/plugin_presets/10.json b/default_presets/plugin_presets/10.json new file mode 100644 index 0000000..3e16c07 --- /dev/null +++ b/default_presets/plugin_presets/10.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamGate","presets": [{"instanceId": 1,"label": "Default","controlValues": {"att": 50,"close": -50,"mak": 0,"mode": 0,"rel": 100,"sidechain": 0,"thr": -60}}],"nextInstanceId": 2} \ No newline at end of file diff --git a/default_presets/plugin_presets/11.json b/default_presets/plugin_presets/11.json new file mode 100644 index 0000000..2469e52 --- /dev/null +++ b/default_presets/plugin_presets/11.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamGateX2","presets": [{"instanceId": 1,"label": "Default","controlValues": {"att": 50,"close": -50,"mak": 0,"mode": 0,"rel": 100,"sidechain": 0,"thr": -60}}],"nextInstanceId": 2} \ No newline at end of file diff --git a/default_presets/plugin_presets/12.json b/default_presets/plugin_presets/12.json new file mode 100644 index 0000000..a33212f --- /dev/null +++ b/default_presets/plugin_presets/12.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamGrains","presets": [ ],"nextInstanceId": 1} \ No newline at end of file diff --git a/default_presets/plugin_presets/13.json b/default_presets/plugin_presets/13.json new file mode 100644 index 0000000..6db5588 --- /dev/null +++ b/default_presets/plugin_presets/13.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamHeadX2","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"az": 0,"elev": 0,"width": 1}}],"nextInstanceId": 2} \ No newline at end of file diff --git a/default_presets/plugin_presets/14.json b/default_presets/plugin_presets/14.json new file mode 100644 index 0000000..6bf0a82 --- /dev/null +++ b/default_presets/plugin_presets/14.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamPhono","presets": [ ],"nextInstanceId": 1} \ No newline at end of file diff --git a/default_presets/plugin_presets/15.json b/default_presets/plugin_presets/15.json new file mode 100644 index 0000000..057c299 --- /dev/null +++ b/default_presets/plugin_presets/15.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamTube","presets": [ ],"nextInstanceId": 1} \ No newline at end of file diff --git a/default_presets/plugin_presets/16.json b/default_presets/plugin_presets/16.json new file mode 100644 index 0000000..71771df --- /dev/null +++ b/default_presets/plugin_presets/16.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamVerb","presets": [ ],"nextInstanceId": 1} \ No newline at end of file diff --git a/default_presets/plugin_presets/17.json b/default_presets/plugin_presets/17.json new file mode 100644 index 0000000..b55196b --- /dev/null +++ b/default_presets/plugin_presets/17.json @@ -0,0 +1 @@ +{"pluginUri": "http://two-play.com/plugins/toob-delay","presets": [{"instanceId": 1,"label": "Classic","controlValues": {"delay": 340,"feedback": 39.1666679,"level": 27}},{"instanceId": 2,"label": "Slapback","controlValues": {"delay": 94.6446991,"feedback": 39.1666679,"level": 42}}],"nextInstanceId": 3} \ No newline at end of file diff --git a/default_presets/plugin_presets/18.json b/default_presets/plugin_presets/18.json new file mode 100644 index 0000000..bde3480 --- /dev/null +++ b/default_presets/plugin_presets/18.json @@ -0,0 +1 @@ +{"pluginUri": "http://two-play.com/plugins/toob-ml","presets": [{"instanceId": 1,"label": "Fender Clean","controlValues": {"bass": 0.783333361,"gain": 0,"master": 1.5,"mid": 0.5,"model": 8,"treble": 0.550000012,"trim": -3}},{"instanceId": 2,"label": "Mesa Crunch","controlValues": {"bass": 0.650000036,"gain": 0,"master": 1.5,"mid": 0.5,"model": 17,"treble": 0.550000012,"trim": -3}},{"instanceId": 3,"label": "Sparkling Clean","controlValues": {"bass": 0.650000036,"gain": 0,"master": 1.5,"mid": 0.5,"model": 19,"treble": 0.550000012,"trim": -3}}],"nextInstanceId": 4} \ No newline at end of file diff --git a/default_presets/plugin_presets/2.json b/default_presets/plugin_presets/2.json new file mode 100644 index 0000000..cfc3227 --- /dev/null +++ b/default_presets/plugin_presets/2.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZaMultiComp","presets": [{"instanceId": 1,"label": "Presence","controlValues": {"att1": 10,"att2": 10,"att3": 10,"globalgain": 0,"kn1": 3,"kn2": 3,"kn3": 3,"listen1": 0,"listen2": 0,"listen3": 0,"mak1": 9,"mak2": 6,"mak3": 6,"rat1": 5,"rat2": 5,"rat3": 5,"rel1": 200,"rel2": 200,"rel3": 200,"thr1": -20,"thr2": -18,"thr3": -16,"toggle1": 1,"toggle2": 1,"toggle3": 1,"xover1": 160,"xover2": 1400}},{"instanceId": 2,"label": "Zero","controlValues": {"att1": 10,"att2": 10,"att3": 10,"globalgain": 0,"kn1": 0,"kn2": 0,"kn3": 0,"listen1": 0,"listen2": 0,"listen3": 0,"mak1": 0,"mak2": 0,"mak3": 0,"rat1": 4,"rat2": 4,"rat3": 4,"rel1": 80,"rel2": 80,"rel3": 80,"thr1": -20,"thr2": -18,"thr3": -16,"toggle1": 0,"toggle2": 0,"toggle3": 0,"xover1": 160,"xover2": 1400}}],"nextInstanceId": 3} \ No newline at end of file diff --git a/default_presets/plugin_presets/3.json b/default_presets/plugin_presets/3.json new file mode 100644 index 0000000..58dd9ae --- /dev/null +++ b/default_presets/plugin_presets/3.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZaMultiCompX2","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"att1": 10,"att2": 10,"att3": 10,"globalgain": 0,"kn1": 0,"kn2": 0,"kn3": 0,"listen1": 0,"listen2": 0,"listen3": 0,"mak1": 0,"mak2": 0,"mak3": 0,"rat1": 4,"rat2": 4,"rat3": 4,"rel1": 80,"rel2": 80,"rel3": 80,"stereodet": 1,"thr1": -20,"thr2": -18,"thr3": -16,"toggle1": 0,"toggle2": 0,"toggle3": 0,"xover1": 160,"xover2": 1400}},{"instanceId": 2,"label": "Presence","controlValues": {"att1": 10,"att2": 10,"att3": 10,"globalgain": 0,"kn1": 3,"kn2": 3,"kn3": 3,"listen1": 0,"listen2": 0,"listen3": 0,"mak1": 9,"mak2": 6,"mak3": 6,"rat1": 5,"rat2": 5,"rat3": 5,"rel1": 200,"rel2": 200,"rel3": 200,"stereodet": 1,"thr1": -20,"thr2": -18,"thr3": -16,"toggle1": 1,"toggle2": 1,"toggle3": 1,"xover1": 160,"xover2": 1400}}],"nextInstanceId": 3} \ No newline at end of file diff --git a/default_presets/plugin_presets/4.json b/default_presets/plugin_presets/4.json new file mode 100644 index 0000000..8194191 --- /dev/null +++ b/default_presets/plugin_presets/4.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamComp","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"att": 10,"kn": 0,"mak": 0,"rat": 4,"rel": 80,"sidech": 0,"slew": 1,"thr": 0}},{"instanceId": 2,"label": "VocalLeveller","controlValues": {"att": 50,"kn": 8,"mak": 9,"rat": 5,"rel": 400,"sidech": 0,"slew": 1,"thr": -16}},{"instanceId": 3,"label": "PoppySnare","controlValues": {"att": 10,"kn": 1,"mak": 6,"rat": 5,"rel": 10,"sidech": 0,"slew": 20,"thr": -18}}],"nextInstanceId": 4} \ No newline at end of file diff --git a/default_presets/plugin_presets/5.json b/default_presets/plugin_presets/5.json new file mode 100644 index 0000000..d355ddf --- /dev/null +++ b/default_presets/plugin_presets/5.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamCompX2","presets": [{"instanceId": 1,"label": "PoppySnare","controlValues": {"att": 10,"kn": 1,"mak": 6,"rat": 5,"rel": 10,"sidechain": 0,"slew": 20,"stereodet": 1,"thr": -18}},{"instanceId": 2,"label": "VocalLeveller","controlValues": {"att": 50,"kn": 8,"mak": 9,"rat": 5,"rel": 400,"sidechain": 0,"slew": 1,"stereodet": 1,"thr": -16}},{"instanceId": 3,"label": "Zero","controlValues": {"att": 10,"kn": 0,"mak": 0,"rat": 4,"rel": 80,"sidechain": 0,"slew": 1,"stereodet": 0,"thr": 0}}],"nextInstanceId": 4} \ No newline at end of file diff --git a/default_presets/plugin_presets/6.json b/default_presets/plugin_presets/6.json new file mode 100644 index 0000000..5986d9f --- /dev/null +++ b/default_presets/plugin_presets/6.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamDelay","presets": [ ],"nextInstanceId": 1} \ No newline at end of file diff --git a/default_presets/plugin_presets/7.json b/default_presets/plugin_presets/7.json new file mode 100644 index 0000000..927ef51 --- /dev/null +++ b/default_presets/plugin_presets/7.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamDynamicEQ","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"att": 10,"boostcut": 0,"detectfreq": 1000,"kn": 0,"max": 10,"rat": 1.5,"rel": 80,"sidech": 0,"slew": 1,"targetfreq": 1000,"targetwidth": 1,"thr": 0,"togglehigh": 0,"togglelow": 0,"togglepeak": 1}},{"instanceId": 2,"label": "PoppySnare","controlValues": {"att": 10,"boostcut": 0,"detectfreq": 1000,"kn": 1,"max": 10,"rat": 1.5,"rel": 10,"sidech": 0,"slew": 20,"targetfreq": 1000,"targetwidth": 1,"thr": -18,"togglehigh": 0,"togglelow": 0,"togglepeak": 1}}],"nextInstanceId": 3} \ No newline at end of file diff --git a/default_presets/plugin_presets/8.json b/default_presets/plugin_presets/8.json new file mode 100644 index 0000000..6d81e80 --- /dev/null +++ b/default_presets/plugin_presets/8.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamEQ2","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"boost1": 0,"boost2": 0,"boosth": 0,"boostl": 0,"bw1": 1,"bw2": 1,"f1": 500,"f2": 3000,"fh": 8000,"fl": 250,"master": 0,"peaks": 0}},{"instanceId": 2,"label": "CarvedBass","controlValues": {"boost1": 0,"boost2": 0,"boosth": 0,"boostl": 6,"bw1": 1,"bw2": 1,"f1": 500,"f2": 3000,"fh": 8000,"fl": 60,"master": -6,"peaks": 0}},{"instanceId": 3,"label": "CarvedVox","controlValues": {"boost1": 0,"boost2": 0,"boosth": 6,"boostl": 6,"bw1": 1,"bw2": 1,"f1": 500,"f2": 3000,"fh": 330,"fl": 6600,"master": -12,"peaks": 0}},{"instanceId": 4,"label": "CarvedGuitar","controlValues": {"boost1": 5.5999999,"boost2": 0.699999988,"boosth": 0,"boostl": -1.04999995,"bw1": 1.46000004,"bw2": 1.33000004,"f1": 175,"f2": 500,"fh": 8000,"fl": 30,"master": -6,"peaks": 0}}],"nextInstanceId": 5} \ No newline at end of file diff --git a/default_presets/plugin_presets/9.json b/default_presets/plugin_presets/9.json new file mode 100644 index 0000000..b7c1c78 --- /dev/null +++ b/default_presets/plugin_presets/9.json @@ -0,0 +1 @@ +{"pluginUri": "urn:zamaudio:ZamGEQ31","presets": [{"instanceId": 1,"label": "Default","controlValues": {"band1": 0,"band10": 0,"band11": 0,"band12": 0,"band13": 0,"band14": 0,"band15": 0,"band16": 0,"band17": 0,"band18": 0,"band19": 0,"band2": 0,"band20": 0,"band21": 0,"band22": 0,"band23": 0,"band24": 0,"band25": 0,"band26": 0,"band27": 0,"band28": 0,"band29": 0,"band3": 0,"band4": 0,"band5": 0,"band6": 0,"band7": 0,"band8": 0,"band9": 0,"master": 0}}],"nextInstanceId": 2} \ No newline at end of file diff --git a/default_presets/plugin_presets/index.json b/default_presets/plugin_presets/index.json new file mode 100644 index 0000000..f3fda51 --- /dev/null +++ b/default_presets/plugin_presets/index.json @@ -0,0 +1 @@ +{"entries": [{"pluginUri": "urn:zamaudio:ZaMaximX2","fileName": "1.json"},{"pluginUri": "urn:zamaudio:ZaMultiComp","fileName": "2.json"},{"pluginUri": "urn:zamaudio:ZaMultiCompX2","fileName": "3.json"},{"pluginUri": "urn:zamaudio:ZamComp","fileName": "4.json"},{"pluginUri": "urn:zamaudio:ZamCompX2","fileName": "5.json"},{"pluginUri": "urn:zamaudio:ZamDelay","fileName": "6.json"},{"pluginUri": "urn:zamaudio:ZamDynamicEQ","fileName": "7.json"},{"pluginUri": "urn:zamaudio:ZamEQ2","fileName": "8.json"},{"pluginUri": "urn:zamaudio:ZamGEQ31","fileName": "9.json"},{"pluginUri": "urn:zamaudio:ZamGate","fileName": "10.json"},{"pluginUri": "urn:zamaudio:ZamGateX2","fileName": "11.json"},{"pluginUri": "urn:zamaudio:ZamGrains","fileName": "12.json"},{"pluginUri": "urn:zamaudio:ZamHeadX2","fileName": "13.json"},{"pluginUri": "urn:zamaudio:ZamPhono","fileName": "14.json"},{"pluginUri": "urn:zamaudio:ZamTube","fileName": "15.json"},{"pluginUri": "urn:zamaudio:ZamVerb","fileName": "16.json"},{"pluginUri": "http://two-play.com/plugins/toob-delay","fileName": "17.json"},{"pluginUri": "http://two-play.com/plugins/toob-ml","fileName": "18.json"}],"nextInstanceId": 19} \ No newline at end of file diff --git a/default_presets/presets/Default+Bank.bank b/default_presets/presets/Default+Bank.bank new file mode 100644 index 0000000..3f10372 --- /dev/null +++ b/default_presets/presets/Default+Bank.bank @@ -0,0 +1 @@ +{"name": "","nextInstanceId": 20,"selectedPreset": 13,"presets": [{"instanceId": 13,"preset": {"name": "Jazz","items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -49.1093903},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -80},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}]},{"instanceId": 18,"uri": "http://two-play.com/plugins/toob-tone-stack","isEnabled": true,"controlValues": [{"key": "bass","value": 0.11666666},{"key": "mid","value": 0.5},{"key": "treble","value": 0.283333331},{"key": "ampmodel","value": 1}],"pluginName": "TooB Tone Stack","midiBindings": [ ]},{"instanceId": 30,"uri": "http://two-play.com/plugins/toob-power-stage-2","isEnabled": true,"controlValues": [{"key": "trim1","value": 0},{"key": "locut1","value": 30},{"key": "hicut1","value": 19000},{"key": "shape1","value": 0},{"key": "gain1","value": 0.458333343},{"key": "bias1","value": 0},{"key": "trim2","value": 0},{"key": "locut2","value": 30},{"key": "hicut2","value": 19000},{"key": "shape2","value": 0},{"key": "gain2","value": 0.383333325},{"key": "bias2","value": 0},{"key": "gain2_enable","value": 1},{"key": "trim3","value": 0},{"key": "locut3","value": 30},{"key": "hicut3","value": 19000},{"key": "shape3","value": 0},{"key": "gain3","value": 0},{"key": "bias3","value": 0},{"key": "gain3_enable","value": 1},{"key": "sag","value": 0.316666663},{"key": "sagd","value": 0.325000018},{"key": "master","value": -12.75},{"key": "sagf","value": 13}],"pluginName": "TooB Power Stage","midiBindings": [ ]},{"instanceId": 20,"uri": "http://two-play.com/plugins/toob-cab-sim","isEnabled": true,"controlValues": [{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "comb","value": 0},{"key": "combf","value": 2000},{"key": "trim","value": 0}],"pluginName": "TooB Cab Simulator","midiBindings": [ ]},{"instanceId": 33,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 12},{"key": "feedback","value": 39}],"pluginName": "TooB Delay","midiBindings": [ ]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": false,"controlValues": [{"key": "dryWet","value": 0.300000012},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.491666675}],"pluginName": "TooB Freeverb","midiBindings": [ ]}],"nextInstanceId": 33}},{"instanceId": 15,"preset": {"name": "Jazz ML","items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -23.1093884},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -80},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}]},{"instanceId": 37,"uri": "uri://two-play/pipedal/pedalboard#Empty","isEnabled": true,"controlValues": [ ],"pluginName": "","midiBindings": [ ]},{"instanceId": 38,"uri": "uri://two-play/pipedal/pedalboard#Empty","isEnabled": true,"controlValues": [ ],"pluginName": "","midiBindings": [ ]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "bass","value": 0.5},{"key": "mid","value": 0.5},{"key": "treble","value": 0.5},{"key": "model","value": 0},{"key": "gain","value": 3},{"key": "master","value": 0}],"pluginName": "TooB ML Amplifier","midiBindings": [ ]},{"instanceId": 35,"uri": "uri://two-play/pipedal/pedalboard#Empty","isEnabled": true,"controlValues": [ ],"pluginName": "","midiBindings": [ ]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.150000006},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ]}],"nextInstanceId": 39}},{"instanceId": 17,"preset": {"name": "Sparkling Clean","items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -23.1093884},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -80},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}]},{"instanceId": 42,"uri": "http://two-play.com/plugins/toob-chorus","isEnabled": false,"controlValues": [{"key": "rate","value": 0.291666657},{"key": "depth","value": 0.375}],"pluginName": "TooB CE-2 Chorus","midiBindings": [ ]},{"instanceId": 41,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 27},{"key": "feedback","value": 39}],"pluginName": "TooB Delay","midiBindings": [ ]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": -3},{"key": "bass","value": 0.650000036},{"key": "mid","value": 0.5},{"key": "treble","value": 0.550000012},{"key": "model","value": 19},{"key": "gain","value": 0},{"key": "master","value": 1.5}],"pluginName": "TooB ML Amplifier","midiBindings": [ ]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.150000006},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ]}],"nextInstanceId": 45}},{"instanceId": 18,"preset": {"name": "Light Crunch","items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -23.1093884},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -80},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}]},{"instanceId": 42,"uri": "http://two-play.com/plugins/toob-chorus","isEnabled": false,"controlValues": [{"key": "rate","value": 0.291666657},{"key": "depth","value": 0.375}],"pluginName": "TooB CE-2 Chorus","midiBindings": [ ]},{"instanceId": 41,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 27},{"key": "feedback","value": 39}],"pluginName": "TooB Delay","midiBindings": [ ]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 2.5},{"key": "bass","value": 0.650000036},{"key": "mid","value": 0.5},{"key": "treble","value": 0.266666681},{"key": "model","value": 17},{"key": "gain","value": 0},{"key": "master","value": 2}],"pluginName": "TooB ML Amplifier","midiBindings": [ ]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.150000006},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ]}],"nextInstanceId": 45}},{"instanceId": 19,"preset": {"name": "Heavy","items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -23.1093884},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -65.5},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}]},{"instanceId": 42,"uri": "http://two-play.com/plugins/toob-chorus","isEnabled": false,"controlValues": [{"key": "rate","value": 0.291666657},{"key": "depth","value": 0.375}],"pluginName": "TooB CE-2 Chorus","midiBindings": [ ]},{"instanceId": 41,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 27},{"key": "feedback","value": 39.1666679}],"pluginName": "TooB Delay","midiBindings": [ ]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 2.5},{"key": "bass","value": 0.650000036},{"key": "mid","value": 0.5},{"key": "treble","value": 0.266666681},{"key": "model","value": 18},{"key": "gain","value": 0},{"key": "master","value": -10}],"pluginName": "TooB ML Amplifier","midiBindings": [ ]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.150000006},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ]}],"nextInstanceId": 45}},{"instanceId": 20,"preset": {"name": "Scream","items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -54},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": -15.75},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -64.5},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}]},{"instanceId": 47,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 12.5},{"key": "model","value": 29},{"key": "gain","value": 3},{"key": "master","value": 6.5},{"key": "bass","value": 0.5},{"key": "mid","value": 0.5},{"key": "treble","value": 0.5}],"pluginName": "TooB ML Amplifier","midiBindings": [ ]},{"instanceId": 42,"uri": "http://two-play.com/plugins/toob-chorus","isEnabled": false,"controlValues": [{"key": "rate","value": 0.291666657},{"key": "depth","value": 0.375}],"pluginName": "TooB CE-2 Chorus","midiBindings": [ ]},{"instanceId": 41,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 10.333333},{"key": "feedback","value": 39.1666679}],"pluginName": "TooB Delay","midiBindings": [ ]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 2.5},{"key": "bass","value": 0.5},{"key": "mid","value": 0.5},{"key": "treble","value": 0.5},{"key": "model","value": 12},{"key": "gain","value": 10},{"key": "master","value": -10}],"pluginName": "TooB ML Amplifier","midiBindings": [ ]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.0416666716},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ]}],"nextInstanceId": 47}}]} \ No newline at end of file diff --git a/default_presets/presets/index.banks b/default_presets/presets/index.banks new file mode 100644 index 0000000..43e2843 --- /dev/null +++ b/default_presets/presets/index.banks @@ -0,0 +1 @@ +{"selectedBank": 1,"nextInstanceId": 1,"entries": [{"instanceId": 1,"name": "Default Bank"}]} \ No newline at end of file diff --git a/react/public/var/config.json b/react/public/var/config.json index 2d62624..20919e1 100644 --- a/react/public/var/config.json +++ b/react/public/var/config.json @@ -1,11 +1,8 @@ { - "socket_server_port": 80, - "socket_server_address": "*", - "debug": true, + "socket_server_port": 8080, + "socket_server_address": "*", + "debug": true, "max_upload_size": 1048576, - - "ui_plugins": [ - - ] - -} \ No newline at end of file + "fakeAndroid": true, + "ui_plugins": [] +} \ No newline at end of file diff --git a/react/src/AndroidHost.tsx b/react/src/AndroidHost.tsx new file mode 100644 index 0000000..1d9fd90 --- /dev/null +++ b/react/src/AndroidHost.tsx @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Copyright (c) 2022 Robin E. R. Davies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +export interface AndroidHostInterface { + isAndroidHosted(): boolean; + getHostVersion() : string; + chooseNewDevice() : void; + onLostConnection(): void; + +}; + +export class FakeAndroidHost implements AndroidHostInterface +{ + isAndroidHosted(): boolean { + return true; + } + getHostVersion(): string { + return "Fake Android 1.0"; + } + chooseNewDevice(): void { + + } + onLostConnection(): void { + + } + +} \ No newline at end of file diff --git a/react/src/App.tsx b/react/src/App.tsx index 055e1e0..b854f5a 100644 --- a/react/src/App.tsx +++ b/react/src/App.tsx @@ -36,7 +36,7 @@ declare module '@mui/styles/defaultTheme' { const theme = createTheme({ palette: { primary: { - main: "#324c6c" + main: "#6750A4" }, secondary: { main: "#FF6060" diff --git a/react/src/AppThemed.tsx b/react/src/AppThemed.tsx index 8d1bd41..334c261 100644 --- a/react/src/AppThemed.tsx +++ b/react/src/AppThemed.tsx @@ -292,7 +292,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< isDrawerOpen: false, errorMessage: this.model_.errorMessage.get(), displayState: this.model_.state.get(), - canFullScreen: supportsFullScreen(), + canFullScreen: supportsFullScreen() && !this.model_.isAndroidHosted(), isFullScreen: !!document.fullscreenElement, tinyToolBar: false, alertDialogOpen: false, @@ -537,7 +537,10 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< setDisplayState(newState: State): void { this.updateOverscroll(); - this.setState({ displayState: newState }); + this.setState({ + displayState: newState, + canFullScreen: supportsFullScreen() && !this.model_.isAndroidHosted() + }); } showDrawer() { diff --git a/react/src/MainPage.tsx b/react/src/MainPage.tsx index 4482a45..336ebb8 100644 --- a/react/src/MainPage.tsx +++ b/react/src/MainPage.tsx @@ -83,7 +83,7 @@ const styles = ({ palette }: Theme) => createStyles({ controlContentSmall: { flex: "0 0 162px", width: "100%", height: 162, overflowY: "hidden", }, - title: { fontSize: "1.3em", fontWeight: 700, marginRight: 8 }, + title: { fontSize: "1.1em", fontWeight: 700, marginRight: 8 }, author: { fontWeight: 500, marginRight: 8 } }); @@ -103,6 +103,7 @@ interface MainState { horizontalScrollLayout: boolean; showMidiBindingsDialog: boolean; screenHeight: number; + } @@ -126,7 +127,7 @@ export const MainPage = splitControlBar: this.windowSize.width < SPLIT_CONTROLBAR_THRESHHOLD, horizontalScrollLayout: this.windowSize.height < HORIZONTAL_CONTROL_SCROLL_HEIGHT_BREAK, showMidiBindingsDialog: false, - screenHeight: this.windowSize.height, + screenHeight: this.windowSize.height }; this.onSelectionChanged = this.onSelectionChanged.bind(this); @@ -465,6 +466,7 @@ export const MainPage = onClick={this.onLoadClick} disabled={this.state.selectedPedal === -1 || (this.getSelectedPedalBoardItem()?.isSplit() ?? true)} startIcon={} + style={{ borderRadius: 24, paddingLeft: 18, paddingRight: 18, textTransform: "none"}} > Load diff --git a/react/src/PiPedalModel.tsx b/react/src/PiPedalModel.tsx index 1e8648e..b35e18e 100644 --- a/react/src/PiPedalModel.tsx +++ b/react/src/PiPedalModel.tsx @@ -33,9 +33,11 @@ import JackServerSettings from './JackServerSettings'; import MidiBinding from './MidiBinding'; import { PluginUiPresets } from './PluginPreset'; import WifiConfigSettings from './WifiConfigSettings'; +import WifiDirectConfigSettings from './WifiDirectConfigSettings'; import GovernorSettings from './GovernorSettings'; import WifiChannel from './WifiChannel'; import AlsaDeviceInfo from './AlsaDeviceInfo'; +import { AndroidHostInterface, FakeAndroidHost } from './AndroidHost'; export enum State { @@ -321,6 +323,7 @@ export interface PiPedalModel { banks: ObservableProperty; jackServerSettings: ObservableProperty; wifiConfigSettings: ObservableProperty; + wifiDirectConfigSettings: ObservableProperty; governorSettings: ObservableProperty; favorites: ObservableProperty; @@ -418,6 +421,7 @@ export interface PiPedalModel { uploadBank(file: File, uploadAfter: number): Promise; setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise; + setWifiDirectConfigSettings(wifiDirectConfigSettings: WifiDirectConfigSettings): Promise; setGovernorSettings(governor: string): Promise; getWifiChannels(countryIso3661: string): Promise; @@ -428,6 +432,10 @@ export interface PiPedalModel { clearZoomedControl(): void; setFavorite(pluginUrl: string, isFavorite: boolean): void; + + isAndroidHosted(): boolean; + getAndroidHostVersion(): string; + chooseNewDevice(): void; }; class PiPedalModelImpl implements PiPedalModel { @@ -457,6 +465,7 @@ class PiPedalModelImpl implements PiPedalModel { = new ObservableProperty(new JackServerSettings()); wifiConfigSettings: ObservableProperty = new ObservableProperty(new WifiConfigSettings()); + wifiDirectConfigSettings: ObservableProperty = new ObservableProperty(new WifiDirectConfigSettings()); governorSettings: ObservableProperty = new ObservableProperty(new GovernorSettings()); favorites: ObservableProperty = new ObservableProperty({}); @@ -484,8 +493,11 @@ class PiPedalModelImpl implements PiPedalModel { return null; } + androidHost?: AndroidHostInterface; constructor() { + this.androidHost = (window as any).AndroidHost as AndroidHostInterface; + this.onSocketError = this.onSocketError.bind(this); this.onSocketMessage = this.onSocketMessage.bind(this); this.onSocketReconnecting = this.onSocketReconnecting.bind(this); @@ -505,23 +517,20 @@ class PiPedalModelImpl implements PiPedalModel { this.onError(errorMessage); } - compareFavorites(left: FavoritesList, right: FavoritesList): boolean - { - for (let key of Object.keys(left)) - { + compareFavorites(left: FavoritesList, right: FavoritesList): boolean { + for (let key of Object.keys(left)) { if (!right[key]) { return false; } } - for (let key of Object.keys(right)) - { + for (let key of Object.keys(right)) { if (!left[key]) { return false; } } return true; - + } onSocketMessage(header: PiPedalMessageHeader, body?: any) { if (this.visibilityState.get() === VisibilityState.Hidden) return; @@ -539,11 +548,9 @@ class PiPedalModelImpl implements PiPedalModel { if (header.replyTo) { this.webSocket?.reply(header.replyTo, "onMonitorPortOutput", true); } - } else if (message === "onFavoritesChanged") - { + } else if (message === "onFavoritesChanged") { let favorites = body as FavoritesList; - if (!this.compareFavorites(favorites,this.favorites.get())) - { + if (!this.compareFavorites(favorites, this.favorites.get())) { this.favorites.set(favorites); } } else if (message === "onChannelSelectionChanged") { @@ -613,6 +620,9 @@ class PiPedalModelImpl implements PiPedalModel { } else if (message === "onWifiConfigSettingsChanged") { let wifiConfigSettings = new WifiConfigSettings().deserialize(body); this.wifiConfigSettings.set(wifiConfigSettings); + } else if (message === "onWifiDirectConfigSettingsChanged") { + let wifiDirectConfigSettings = new WifiDirectConfigSettings().deserialize(body); + this.wifiDirectConfigSettings.set(wifiDirectConfigSettings); } else if (message === "onGovernorSettingsChanged") { let governor = body as string; @@ -704,10 +714,17 @@ class PiPedalModelImpl implements PiPedalModel { .then(data => { this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data)); - return this.getWebSocket().request("getGovernorSettings"); - }) - .then(data => { - this.governorSettings.set(new GovernorSettings().deserialize(data)); + + return this.getWebSocket().request("getWifiDirectConfigSettings"); + }) + .then(data => { + this.wifiDirectConfigSettings.set(new WifiDirectConfigSettings().deserialize(data)); + + + return this.getWebSocket().request("getGovernorSettings"); + }) + .then(data => { + this.governorSettings.set(new GovernorSettings().deserialize(data)); return this.getWebSocket().request("getJackServerSettings"); @@ -740,7 +757,7 @@ class PiPedalModelImpl implements PiPedalModel { return this.getWebSocket().request("getFavorites"); }) - .then((data)=> { + .then((data) => { this.favorites.set(data); this.setState(State.Ready); @@ -773,6 +790,9 @@ class PiPedalModelImpl implements PiPedalModel { if (data.max_upload_size) { this.maxUploadSize = data.max_upload_size; } + if (data.fakeAndroid) { + this.androidHost = new FakeAndroidHost(); + } this.debug = !!data.debug; let { socket_server_port, socket_server_address } = data; if ((!socket_server_address) || socket_server_address === "*") { @@ -843,15 +863,21 @@ class PiPedalModelImpl implements PiPedalModel { }) .then((data) => { this.presets.set(new PresetIndex().deserialize(data)); + return this.getWebSocket().request("getWifiConfigSettings"); }) .then(data => { this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data)); - return this.getWebSocket().request("getGovernorSettings"); - }) - .then(data => { - this.governorSettings.set(new GovernorSettings().deserialize(data)); + return this.getWebSocket().request("getWifiDirectConfigSettings"); + }) + .then(data => { + this.wifiDirectConfigSettings.set(new WifiDirectConfigSettings().deserialize(data)); + + return this.getWebSocket().request("getGovernorSettings"); + }) + .then(data => { + this.governorSettings.set(new GovernorSettings().deserialize(data)); return this.getWebSocket().request("getJackServerSettings"); @@ -876,19 +902,17 @@ class PiPedalModelImpl implements PiPedalModel { }) .then((data) => { this.banks.set(new BankIndex().deserialize(data)); - if (this.webSocket) - { + if (this.webSocket) { // MUST not allow reconnect until at least one complete load has finished. this.webSocket.canReconnect = true; } return this.getWebSocket().request("getFavorites"); }) - .then((data)=> { + .then((data) => { this.favorites.set(data); - if (this.webSocket) - { + if (this.webSocket) { // MUST not allow reconnect until at least one complete load has finished. this.webSocket.canReconnect = true; } @@ -1901,6 +1925,57 @@ class PiPedalModelImpl implements PiPedalModel { }); return result; } + setWifiDirectConfigSettings(wifiDirectConfigSettings: WifiDirectConfigSettings): Promise { + let result = new Promise((resolve, reject) => { + let oldSettings = this.wifiDirectConfigSettings.get(); + wifiDirectConfigSettings = wifiDirectConfigSettings.clone(); + + if ((!oldSettings.enable) && (!wifiDirectConfigSettings.enable)) { + // no effective change. + resolve(); + return; + } + if (!wifiDirectConfigSettings.enable) { + wifiDirectConfigSettings = oldSettings.clone(); + wifiDirectConfigSettings.enable = false; + } else { + if (wifiDirectConfigSettings.countryCode === oldSettings.countryCode + && wifiDirectConfigSettings.channel === oldSettings.channel + && wifiDirectConfigSettings.hotspotName === oldSettings.hotspotName + && wifiDirectConfigSettings.enable == oldSettings.enable) { + if (wifiDirectConfigSettings.pin === oldSettings.pin) { + // no effective change. + resolve(); + return; + } + } + } + // save a version for the server (potentially carrying a password) + let serverConfigSettings = wifiDirectConfigSettings.clone(); + this.wifiDirectConfigSettings.set(wifiDirectConfigSettings); + + + + // notify the server. + let ws = this.webSocket; + if (!ws) { + reject("Not connected."); + return; + } + ws.request( + "setWifiDirectConfigSettings", + serverConfigSettings + ) + .then(() => { + resolve(); + }) + .catch((err) => { + reject(err); + }); + + }); + return result; + } getWifiChannels(countryIso3661: string): Promise { let result = new Promise((resolve, reject) => { @@ -1939,24 +2014,20 @@ class PiPedalModelImpl implements PiPedalModel { this.zoomedUiControl.set(undefined); } - setFavorite(pluginUrl: string, isFavorite: boolean): void - { + setFavorite(pluginUrl: string, isFavorite: boolean): void { let favorites = this.favorites.get(); let newFavorites: FavoritesList = {}; - Object.assign(newFavorites,favorites); - if (isFavorite) - { + Object.assign(newFavorites, favorites); + if (isFavorite) { newFavorites[pluginUrl] = true; } else { - if (newFavorites[pluginUrl]) - { + if (newFavorites[pluginUrl]) { delete newFavorites[pluginUrl]; } } this.favorites.set(newFavorites); - if (this.webSocket) - { - this.webSocket.send("setFavorites",newFavorites); + if (this.webSocket) { + this.webSocket.send("setFavorites", newFavorites); } // stub: update server. } @@ -1971,6 +2042,21 @@ class PiPedalModelImpl implements PiPedalModel { } } + isAndroidHosted(): boolean { return this.androidHost !== undefined; } + + getAndroidHostVersion(): string { + if (this.androidHost) { + return this.androidHost.getHostVersion(); + } + return ""; + } + chooseNewDevice(): void { + if (this.androidHost) { + return this.androidHost.chooseNewDevice(); + } + + } + }; let instance: PiPedalModel | undefined = undefined; diff --git a/react/src/SettingsDialog.tsx b/react/src/SettingsDialog.tsx index 65040d3..06f39c3 100644 --- a/react/src/SettingsDialog.tsx +++ b/react/src/SettingsDialog.tsx @@ -35,13 +35,15 @@ import JackServerSettings from './JackServerSettings'; import JackServerSettingsDialog from './JackServerSettingsDialog'; import JackHostStatus from './JackHostStatus'; import WifiConfigSettings from './WifiConfigSettings'; +import WifiDirectConfigSettings from './WifiDirectConfigSettings'; import WifiConfigDialog from './WifiConfigDialog'; +import WifiDirectConfigDialog from './WifiDirectConfigDialog'; import DialogEx from './DialogEx' import GovernorSettings from './GovernorSettings'; -import Slide, {SlideProps} from '@mui/material/Slide'; +import Slide, { SlideProps } from '@mui/material/Slide'; import { createStyles, Theme } from '@mui/material/styles'; -import { WithStyles, withStyles} from '@mui/styles'; +import { WithStyles, withStyles } from '@mui/styles'; @@ -60,8 +62,10 @@ interface SettingsDialogState { governorSettings: GovernorSettings; wifiConfigSettings: WifiConfigSettings; + wifiDirectConfigSettings: WifiDirectConfigSettings; showWifiConfigDialog: boolean; + showWifiDirectConfigDialog: boolean; showGovernorSettingsDialog: boolean; showInputSelectDialog: boolean; showOutputSelectDialog: boolean; @@ -69,6 +73,7 @@ interface SettingsDialogState { showJackServerSettingsDialog: boolean; shuttingDown: boolean; restarting: boolean; + isAndroidHosted: boolean; }; @@ -150,15 +155,19 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( jackStatus: undefined, jackSettings: this.model.jackSettings.get(), wifiConfigSettings: this.model.wifiConfigSettings.get(), - governorSettings: this.model.governorSettings.get(), + wifiDirectConfigSettings: this.model.wifiDirectConfigSettings.get(), + governorSettings: this.model.governorSettings.get(), showWifiConfigDialog: false, + showWifiDirectConfigDialog: false, showGovernorSettingsDialog: false, showInputSelectDialog: false, showOutputSelectDialog: false, showMidiSelectDialog: false, showJackServerSettingsDialog: false, shuttingDown: false, - restarting: false + restarting: false, + isAndroidHosted: this.model.isAndroidHosted() + }; @@ -166,6 +175,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( this.handleJackSettingsChanged = this.handleJackSettingsChanged.bind(this); this.handleJackServerSettingsChanged = this.handleJackServerSettingsChanged.bind(this); this.handleWifiConfigSettingsChanged = this.handleWifiConfigSettingsChanged.bind(this); + this.handleWifiDirectConfigSettingsChanged = this.handleWifiDirectConfigSettingsChanged.bind(this); this.handleGovernorSettingsChanged = this.handleGovernorSettingsChanged.bind(this); this.handleConnectionStateChanged = this.handleConnectionStateChanged.bind(this); @@ -173,6 +183,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( handleConnectionStateChanged(): void { if (this.model.state.get() === State.Ready) { + this.setState({ isAndroidHosted: this.model.isAndroidHosted() }); if (this.state.shuttingDown || this.state.restarting) { this.setState({ shuttingDown: false, restarting: false }); } @@ -189,6 +200,18 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( this.model.showAlert(err); }); } + + handleApplyWifiDirectConfig(wifiDirectConfigSettings: WifiDirectConfigSettings): void { + this.setState({ showWifiDirectConfigDialog: false }); + this.model.setWifiDirectConfigSettings(wifiDirectConfigSettings) + .then(() => { + + }) + .catch((err) => { + this.model.showAlert(err); + }); + } + handleApplyGovernorSettings(governor: string): void { this.model.setGovernorSettings(governor) .then(() => { @@ -206,6 +229,14 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( } ) } + handleWifiDirectConfigSettingsChanged(): void { + this.setState( + { + wifiDirectConfigSettings: this.model.wifiDirectConfigSettings.get() + } + ) + } + handleGovernorSettingsChanged(): void { this.setState( { @@ -257,6 +288,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( this.model.jackConfiguration.addOnChangedHandler(this.handleJackConfigurationChanged); this.model.jackServerSettings.addOnChangedHandler(this.handleJackServerSettingsChanged); this.model.wifiConfigSettings.addOnChangedHandler(this.handleWifiConfigSettingsChanged); + this.model.wifiDirectConfigSettings.addOnChangedHandler(this.handleWifiDirectConfigSettingsChanged); this.model.governorSettings.addOnChangedHandler(this.handleGovernorSettingsChanged); this.model.getJackStatus() .then((jackStatus) => @@ -276,6 +308,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( this.handleJackSettingsChanged(); this.handleJackServerSettingsChanged(); this.handleWifiConfigSettingsChanged(); + this.handleWifiDirectConfigSettingsChanged(); this.timerHandle = setInterval(() => this.tick(), 1000); } else { if (this.timerHandle) { @@ -286,7 +319,8 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( this.model.jackSettings.removeOnChangedHandler(this.handleJackSettingsChanged); this.model.jackServerSettings.removeOnChangedHandler(this.handleJackServerSettingsChanged); this.model.wifiConfigSettings.removeOnChangedHandler(this.handleWifiConfigSettingsChanged); - this.model.wifiConfigSettings.removeOnChangedHandler(this.handleGovernorSettingsChanged); + this.model.wifiDirectConfigSettings.removeOnChangedHandler(this.handleWifiDirectConfigSettingsChanged); + this.model.governorSettings.removeOnChangedHandler(this.handleGovernorSettingsChanged); } } @@ -340,7 +374,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( let newSelection = this.state.jackSettings.clone(); newSelection.inputMidiPorts = channels; this.model.setJackSettings(newSelection); - + } this.setState({ showMidiSelectDialog: false, @@ -385,6 +419,11 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( showWifiConfigDialog: true }); } + handleShowWifiDirectConfigDialog() { + this.setState({ + showWifiDirectConfigDialog: true + }); + } handleShowGovernorSettingsDialogDialog() { this.setState({ showGovernorSettingsDialog: true @@ -461,7 +500,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( (
{JackHostStatus.getDisplayView("", this.state.jackStatus)} - { JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)} + {JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
) } @@ -534,8 +573,42 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
- SYSTEM + CONNECTION + + { + this.state.isAndroidHosted && + ( + this.model.chooseNewDevice() } > + +
+ + Connect to a difference device + + + + +
+
+ ) + } + + this.handleShowWifiDirectConfigDialog()} > + +
+ + Configure Wi-Fi Direct hotspot + + {this.state.wifiDirectConfigSettings.getSummaryText()} + + +
+
+ this.handleShowWifiConfigDialog()} >
@@ -547,8 +620,13 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
+
+ +
+ SYSTEM + this.handleShowGovernorSettingsDialogDialog()} > @@ -556,13 +634,26 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( CPU Governor - {this.state.governorSettings.governor } + {this.state.governorSettings.governor}
- - + + this.handleShowGovernorSettingsDialogDialog()} > + +
+ + Show status monitor on main screen. + + Enabled + + +
+
+ this.handleRestart()} > @@ -571,7 +662,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( this.state.restarting ? ( Rebooting... ) : ( - Reboot + Reboot PiPedal ) } @@ -610,25 +701,25 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( { (this.state.showGovernorSettingsDialog) && ( - this.setState({showGovernorSettingsDialog: false})} + onClose={() => this.setState({ showGovernorSettingsDialog: false })} onOk={(selectedValue) => { this.model.setGovernorSettings(selectedValue) - .then(()=>{ + .then(() => { - }) - .catch(error => { - this.model.showAlert(error); - }); - - this.setState({showGovernorSettingsDialog: false}) + }) + .catch(error => { + this.model.showAlert(error); + }); + + this.setState({ showGovernorSettingsDialog: false }) }} - > + > ) @@ -648,6 +739,10 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( onClose={() => this.setState({ showWifiConfigDialog: false })} onOk={(wifiConfigSettings) => this.handleApplyWifiConfig(wifiConfigSettings)} /> + this.setState({ showWifiDirectConfigDialog: false })} + onOk={(wifiDirectConfigSettings: WifiDirectConfigSettings) => this.handleApplyWifiDirectConfig(wifiDirectConfigSettings)} + /> diff --git a/react/src/TemporaryDrawer.tsx b/react/src/TemporaryDrawer.tsx index d0fc893..98b01c3 100644 --- a/react/src/TemporaryDrawer.tsx +++ b/react/src/TemporaryDrawer.tsx @@ -39,8 +39,8 @@ const drawerStyles = (theme: Theme) => { }, drawer_header: { - color: 'white', - background: theme.palette.primary.main, + color: theme.palette.primary.main, + background: 'white', } })}; diff --git a/react/src/WifiDirectConfigDialog.tsx b/react/src/WifiDirectConfigDialog.tsx new file mode 100644 index 0000000..6bedfd4 --- /dev/null +++ b/react/src/WifiDirectConfigDialog.tsx @@ -0,0 +1,400 @@ +/* + * MIT License + * + * Copyright (c) 2022 Robin E. R. Davies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import React from 'react'; +import Button from '@mui/material/Button'; +import TextField from '@mui/material/TextField'; +import DialogEx from './DialogEx'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; +import Switch from '@mui/material/Switch'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import WifiDirectConfigSettings from './WifiDirectConfigSettings'; +import { Theme } from '@mui/material/styles'; +import { WithStyles } from '@mui/styles'; +import withStyles from '@mui/styles/withStyles'; +import createStyles from '@mui/styles/createStyles'; +import Select from '@mui/material/Select'; +import FormControl from '@mui/material/FormControl'; +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import WifiChannel from './WifiChannel'; +import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; + +const styles = (theme: Theme) => createStyles({ + pgraph: { + paddingBottom: 16 + } +}); + +declare let crypto: any; + +const NBSP = "\u00A0"; + +export interface WifiDirectConfigProps extends WithStyles { + open: boolean, + wifiDirectConfigSettings: WifiDirectConfigSettings, + onOk: (wifiDirectConfigSettings: WifiDirectConfigSettings) => void, + onClose: () => void +} + +export interface WifiDirectConfigState { + fullScreen: boolean; + enabled: boolean; + name: string; + pin: string; + nameError: boolean; + nameErrorMessage: string; + pinError: boolean; + pinErrorMessage: string; + countryCode: string; + channel: string; + wifiChannels: WifiChannel[]; +} + + + +const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })( + class extends ResizeResponsiveComponent { + + refName: React.RefObject; + refPassword: React.RefObject; + model: PiPedalModel; + + constructor(props: WifiDirectConfigProps) { + super(props); + this.model = PiPedalModelFactory.getInstance(); + this.state = { + fullScreen: false, + enabled: this.props.wifiDirectConfigSettings.enable, + name: this.props.wifiDirectConfigSettings.hotspotName, + pin: this.props.wifiDirectConfigSettings.pin, + nameError: false, + nameErrorMessage: NBSP, + pinError: false, + pinErrorMessage: NBSP, + countryCode: this.props.wifiDirectConfigSettings.countryCode, + channel: this.props.wifiDirectConfigSettings.channel, + wifiChannels: [] + }; + this.model.getWifiChannels(this.props.wifiDirectConfigSettings.countryCode) + .then((wifiChannels_) => { + this.setState({ wifiChannels: wifiChannels_ }); + }).catch((err) => { }); + + this.refName = React.createRef(); + this.refPassword = React.createRef(); + } + mounted: boolean = false; + + handleEnableChanged(e: any) { + this.setState({ enabled: e.target.checked }); + } + + + onWindowSizeChanged(width: number, height: number): void { + this.setState({ fullScreen: height < 200 }) + } + + + componentDidMount() { + super.componentDidMount(); + this.mounted = true; + } + componentWillUnmount() { + super.componentWillUnmount(); + this.mounted = false; + } + + componentDidUpdate(prevProps: WifiDirectConfigProps) { + + if (this.props.open && !prevProps.open) { + this.setState({ + enabled: this.props.wifiDirectConfigSettings.enable, + name: this.props.wifiDirectConfigSettings.hotspotName, + pin: this.props.wifiDirectConfigSettings.pin, + countryCode: this.props.wifiDirectConfigSettings.countryCode, + channel: this.props.wifiDirectConfigSettings.channel + }); + + if (this.props.wifiDirectConfigSettings.countryCode !== this.state.countryCode) { + this.model.getWifiChannels(this.props.wifiDirectConfigSettings.countryCode) + .then((wifiChannels) => { + this.setState({ wifiChannels: wifiChannels }); + }) + .catch((error) => { }); + + } + + } + + } + utf8Encode: TextEncoder = new TextEncoder(); + + validateName(name: string): void { + if (name.length === 0) { + throw new RangeError("Required."); + } + let bytes = this.utf8Encode.encode("DIRECT-XX-" + name); + if (bytes.length > 31) { + throw new RangeError("Too long."); + } + } + validatePin(pin: string) { + if (pin.length === 0) throw new Error("Required."); + if (pin.length !== 8) { + throw new RangeError("Must be exactly 8 digits."); + } + for (let i = 0; i < pin.length; ++i) { + let c = pin.charCodeAt(i); + if (c < '0'.charCodeAt(0) || c > '9'.charCodeAt(0)) { + throw new RangeError("Must be exactly 8 digits."); + } + } + } + + handleOk() { + let nameError = false; + let nameErrorMessage = NBSP; + let pinError = false; + let pinErrorMessage = NBSP; + if (this.state.enabled) { + let name = this.state.name; + try { + this.validateName(name); + } catch (e: any) { + nameError = true; nameErrorMessage = "* " + e.message; + } + let pin = this.state.pin; + try { + this.validatePin(pin); + } catch (e: any) { + pinError = true; pinErrorMessage = "* " + e.message; + } + + let error = pinError || nameError || this.state.countryCode === ""; + if (error) { + this.setState({ nameError: nameError, nameErrorMessage: nameErrorMessage, pinError: pinError, pinErrorMessage: pinErrorMessage }); + } else { + let wifiDirectConfigSettings = new WifiDirectConfigSettings(); + wifiDirectConfigSettings.valid = true; + + wifiDirectConfigSettings.enable = this.state.enabled; + wifiDirectConfigSettings.hotspotName = this.state.name; + wifiDirectConfigSettings.countryCode = this.state.countryCode; + wifiDirectConfigSettings.channel = this.state.channel; + wifiDirectConfigSettings.pin = this.state.pin; + this.props.onOk(wifiDirectConfigSettings); + } + } else { + let wifiDirectConfigSettings = new WifiDirectConfigSettings(); + wifiDirectConfigSettings.valid = true; + wifiDirectConfigSettings.enable = false; + this.props.onOk(wifiDirectConfigSettings); + + } + + } + preventPasswordPrompt() { + } + handleChannelChange(e: any) { + let value = e.target.value as string; + this.setState({ channel: value }); + } + handleCountryChanged(e: any) { + let value = e.target.value as string; + + this.setState({ countryCode: value }); + this.model.getWifiChannels(value) + .then(wifiChannels => { + this.setState({ wifiChannels: wifiChannels }); + }) + .catch((error) => { }); + } + + generateRandomPin(): string { + // prefer crypto if it's available. + let zero = "0".charCodeAt(0); + try { + let randomValue = new Int32Array(8); + crypto.getRandomValues(randomValue); + + let s: string = ""; + for (let i = 0; i < 8; ++i) { + let k = randomValue[i]; + if (k < 0) k = -k; + k = k % 10; + + s += String.fromCharCode(zero + k); + } + return s; + + } catch (e) { + + } + let zero2 = "a".charCodeAt(0); + let s2 = ""; + for (let i = 0; i < 8; ++i) { + let k = Math.floor(Math.random() * 10); + if (k < 0) k = -k; + k = k % 10; + + s2 += String.fromCharCode(zero2 + k); + } + return s2; + } + + onGenerateRandomPin() { + let newPin = this.generateRandomPin(); + this.setState({ pin: newPin, pinError: false, pinErrorMessage: NBSP }); + if (this.refPassword.current) { + this.refPassword.current.value = newPin; + } + } + + render() { + let props = this.props; + let { open, onClose } = props; + + const handleClose = () => { + this.preventPasswordPrompt(); + // let preventPasswordPrompt changes settle (it's HARD to prevent a password prompt) + setTimeout(() => { + onClose(); + }, 100); + }; + + return ( + + {this.state.fullScreen && ( + Wi-fi Hotspot + )} + + + this.handleEnableChanged(e)} + color="secondary" + /> + )} + label="Enable Wi-Fi Direct Hotspot" + /> +
+ this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })} + inputRef={this.refName} + disabled={!this.state.enabled} + variant="filled" + /> +
+
+ { this.setState({ pin: e.target.value, pinError: false, pinErrorMessage: NBSP }); }} + label="Pin" + error={this.state.pinError} + helperText={this.state.pinErrorMessage} + defaultValue={this.state.pin} + disabled={!this.state.enabled} + variant="filled" + /> + +
+ +
+
+
+
+ + Country + + + + + +
+
+ + Channel + + + +
+ +
+ + + + +
+ ); + } + }); + +export default WifiDirectConfigDialog; \ No newline at end of file diff --git a/react/src/WifiDirectConfigSettings.tsx b/react/src/WifiDirectConfigSettings.tsx new file mode 100644 index 0000000..f2bd0be --- /dev/null +++ b/react/src/WifiDirectConfigSettings.tsx @@ -0,0 +1,67 @@ +/* + * MIT License + * + * Copyright (c) 2022 Robin E. R. Davies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +export default class WifiDirectConfigSettings { + deserialize(input: any) : WifiDirectConfigSettings{ + this.valid = input.valid; + this.rebootRequired = input.rebootRequired; + this.enable = input.enable; + this.pinChanged = input.pinChanged; + this.hotspotName = input.hotspotName; + this.countryCode = input.countryCode; + this.pin = input.pin; + this.channel = input.channel; + + return this; + } + clone() : WifiDirectConfigSettings { + return new WifiDirectConfigSettings().deserialize(this); + } + valid: boolean = true; + enable: boolean = true; + rebootRequired = false; + hotspotName: string = "pipedal"; + pinChanged: boolean = false; + pin: string = ""; + countryCode: string = "US"; + channel: string = "6"; + + getSummaryText() { + let result: string; + if (!this.valid) { + result = "Not available."; + } else if (!this.enable) { + result = "Disabled."; + } else { + result = this.hotspotName; + } + if (this.rebootRequired) + { + result += " (Restart required)"; + } + return result; + } + +} \ No newline at end of file diff --git a/src/AvahiService.cpp b/src/AvahiService.cpp index 4fbd70b..92e4e11 100644 --- a/src/AvahiService.cpp +++ b/src/AvahiService.cpp @@ -156,7 +156,7 @@ void AvahiService::create_group(AvahiClient *c) if ((ret = avahi_entry_group_add_service( group, AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, + AVAHI_PROTO_INET, // IPv4 for now, until we figure out why dnsqmasq borks IPv6 routing.) (AvahiPublishFlags)0, name, PIPEDAL_SERVICE_TYPE, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 60d48ee..3eb5259 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.16.0) set (CMAKE_INSTALL_PREFIX "/usr/") +set (USE_PCH 1) + include(FindPkgConfig) @@ -95,6 +97,7 @@ set (PIPEDAL_SOURCES P2pConfigFiles.hpp AvahiService.cpp AvahiService.hpp DeviceIdFile.cpp DeviceIdFile.hpp + WriteTemplateFile.cpp WriteTemplateFile.hpp StdErrorCapture.hpp StdErrorCapture.cpp Ipv6Helpers.cpp Ipv6Helpers.hpp @@ -152,30 +155,45 @@ set (PIPEDAL_SOURCES ) + configure_file(config.hpp.in config.hpp) +include_directories( ${pipedald_SOURCE_DIR}/. ../build/src) + +set (PIPEDAL_INCLUDES + ${LV2DEV_INCLUDE_DIRS} + ${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} ${LIBNL3_INCLUDE_DIRS} ${LVDEV_INCLUDE_DIRS} +) + +set(PIPEDAL_LIBS libpipedald pthread atomic stdc++fs asound avahi-common avahi-client systemd + ${LILV_0_LIBRARIES} ${JACK_LIBRARIES} ${LIBNL3_LIBRARIES} ) + + +########################## + +add_library(libpipedald STATIC ${PIPEDAL_SOURCES}) + +target_include_directories(libpipedald PRIVATE ${PIPEDAL_INCLUDES} + ) + +if(${USE_PCH}) + target_precompile_headers(libpipedald PRIVATE pch.h) +endif() + ################################# -add_executable(pipedald ${PIPEDAL_SOURCES} +add_executable(pipedald asan_options.cpp # disable leak checking for sanitize=address. main.cpp ) +target_include_directories(pipedald PRIVATE ${PIPEDAL_INCLUDES}) -include_directories( ${pipedald_SOURCE_DIR}/. ../build/src) - -target_precompile_headers(pipedald PRIVATE pch.h) - - -target_include_directories(pipedald PRIVATE - ${LV2DEV_INCLUDE_DIRS} - ${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} ${LIBNL3_INCLUDE_DIRS} ${LVDEV_INCLUDE_DIRS} - ) - -target_link_libraries(pipedald PRIVATE pthread atomic stdc++fs asound avahi-common avahi-client - ${LILV_0_LIBRARIES} ${JACK_LIBRARIES} ${LIBNL3_LIBRARIES} systemd SDBusCpp::sdbus-c++ +target_link_libraries(pipedald PRIVATE + + ${PIPEDAL_LIBS} ) ################################# -add_executable(pipedaltest ${PIPEDAL_SOURCES} testMain.cpp +add_executable(pipedaltest testMain.cpp jsonTest.cpp AvahiServiceTest.cpp WifiChannelsTest.cpp @@ -192,20 +210,17 @@ add_executable(pipedaltest ${PIPEDAL_SOURCES} testMain.cpp MemDebug.hpp ) -configure_file(config.hpp.in config.hpp) include_directories( ${pipedald_SOURCE_DIR}/. ../build/src) +if(${USE_PCH}) target_precompile_headers(pipedaltest PRIVATE pch.h) +endif() -target_include_directories(pipedaltest PRIVATE - . - ${LV2DEV_INCLUDE_DIRS} - ${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} ${LIBNL3_INCLUDE_DIRS} +target_include_directories(pipedaltest PRIVATE ${PIPEDAL_INCLUDES} ) -target_link_libraries(pipedaltest PRIVATE pthread atomic stdc++fs asound avahi-common avahi-client - ${LILV_0_LIBRARIES} ${JACK_LIBRARIES} ${LIBNL3_LIBRARIES} systemd SDBusCpp::sdbus-c++ +target_link_libraries(pipedaltest PRIVATE ${PIPEDAL_LIBS} ) diff --git a/src/ConfigUtil.cpp b/src/ConfigUtil.cpp index d8d235b..f70beb8 100644 --- a/src/ConfigUtil.cpp +++ b/src/ConfigUtil.cpp @@ -48,7 +48,7 @@ static std::string trim(const std::string &value) size_t start = 0; size_t end = value.length(); - while (start < end && ( value[start] == ' ' || value[start] == '\t')) + while (start < end && (value[start] == ' ' || value[start] == '\t')) ++start; while (end > start && (value[end - 1] == ' ' || value[end - 1] == '\t')) @@ -96,11 +96,36 @@ static std::string unquote(const std::string &value) } return ss.str(); } - } return value; } -bool ConfigUtil::GetConfigLine(const std::string & filePath,const std::string & key, std::string *pValue) + +std::string ConfigUtil::QuoteString(const std::string &value) +{ + std::stringstream s; + + s << '"'; + for (char c : value) + { + switch (c) + { + case '\n': + break; + case '"': + s << "\\\""; + break; + case '\\': + s << "\\\\"; + break; + default: + s << c; + break; + } + } + s << '"'; + return s.str(); +} +bool ConfigUtil::GetConfigLine(const std::string &filePath, const std::string &key, std::string *pValue) { ifstream f; diff --git a/src/ConfigUtil.hpp b/src/ConfigUtil.hpp index 388b292..fcc51ff 100644 --- a/src/ConfigUtil.hpp +++ b/src/ConfigUtil.hpp @@ -30,5 +30,8 @@ namespace pipedal { class ConfigUtil { public: static bool GetConfigLine(const std::string & filePath,const std::string & key, std::string *pValue); + + static std::string QuoteString(const std::string &value); + }; } \ No newline at end of file diff --git a/src/Ipv6Helpers.hpp b/src/Ipv6Helpers.hpp index d790c2e..7acccb8 100644 --- a/src/Ipv6Helpers.hpp +++ b/src/Ipv6Helpers.hpp @@ -19,6 +19,7 @@ #pragma once +#include namespace pipedal { diff --git a/src/PiPedalModel.cpp b/src/PiPedalModel.cpp index 580b52b..d5c188b 100644 --- a/src/PiPedalModel.cpp +++ b/src/PiPedalModel.cpp @@ -678,11 +678,42 @@ void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSet delete[] t; } } +void PiPedalModel::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiDirectConfigSettings) +{ + std::lock_guard guard(mutex); + + adminClient.SetWifiDirectConfig(wifiDirectConfigSettings); + + this->storage.SetWifiDirectConfigSettings(wifiDirectConfigSettings); + + { + IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; + for (size_t i = 0; i < subscribers.size(); ++i) + { + t[i] = this->subscribers[i]; + } + size_t n = this->subscribers.size(); + + WifiDirectConfigSettings tWifiDirectConfigSettings = storage.GetWifiDirectConfigSettings(); // (the passwordless version) + + for (size_t i = 0; i < n; ++i) + { + t[i]->OnWifiDirectConfigSettingsChanged(tWifiDirectConfigSettings); + } + delete[] t; + } +} + WifiConfigSettings PiPedalModel::GetWifiConfigSettings() { std::lock_guard guard(mutex); return this->storage.GetWifiConfigSettings(); } +WifiDirectConfigSettings PiPedalModel::GetWifiDirectConfigSettings() +{ + std::lock_guard guard(mutex); + return this->storage.GetWifiDirectConfigSettings(); +} JackConfiguration PiPedalModel::GetJackConfiguration() { diff --git a/src/PiPedalModel.hpp b/src/PiPedalModel.hpp index ffedd15..c66ac76 100644 --- a/src/PiPedalModel.hpp +++ b/src/PiPedalModel.hpp @@ -33,6 +33,7 @@ #include "PiPedalConfiguration.hpp" #include "JackServerSettings.hpp" #include "WifiConfigSettings.hpp" +#include "WifiDirectConfigSettings.hpp" #include "AdminClient.hpp" @@ -62,6 +63,7 @@ public: virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) = 0; virtual void OnNotifyAtomOutput(int64_t clientModel,uint64_t instanceId,const std::string&atomType, const std::string&atomJson) = 0; virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) = 0; + virtual void OnWifiDirectConfigSettingsChanged(const WifiDirectConfigSettings&wifiDirectConfigSettings) = 0; virtual void OnGovernorSettingsChanged(const std::string &governor) = 0; virtual void OnFavoritesChanged(const std::map &favorites) = 0; virtual void Close() = 0; @@ -207,6 +209,9 @@ public: void SetWifiConfigSettings(const WifiConfigSettings&wifiConfigSettings); WifiConfigSettings GetWifiConfigSettings(); + void SetWifiDirectConfigSettings(const WifiDirectConfigSettings&wifiConfigSettings); + WifiDirectConfigSettings GetWifiDirectConfigSettings(); + void SetGovernorSettings(const std::string& governor); GovernorSettings GetGovernorSettings(); diff --git a/src/PiPedalSocket.cpp b/src/PiPedalSocket.cpp index e870c6e..21d8b52 100644 --- a/src/PiPedalSocket.cpp +++ b/src/PiPedalSocket.cpp @@ -32,6 +32,7 @@ #include "AdminClient.hpp" #include "WifiConfigSettings.hpp" +#include "WifiDirectConfigSettings.hpp" #include "WifiChannels.hpp" #include "SysExec.hpp" #include "PiPedalAlsa.hpp" @@ -812,6 +813,28 @@ public: this->Reply(replyTo, "getWifiConfigSettings", model.GetWifiConfigSettings()); } + else if (message == "setWifiDirectConfigSettings") { + WifiDirectConfigSettings wifiDirectConfigSettings; + pReader->read(&wifiDirectConfigSettings); + if (!GetAdminClient().CanUseShutdownClient()) + { + throw PiPedalException("Can't change server settings when running interactively."); + } + std::string fromAddress = this->getFromAddress(); + if (!IsOnLocalSubnet(fromAddress)) + { + throw PiPedalException("Permission denied. Not on local subnet."); + } + + + this->model.SetWifiDirectConfigSettings(wifiDirectConfigSettings); + this->Reply(replyTo,"setWifiDirectConfigSettings"); + } + else if (message == "getWifiDirectConfigSettings") { + this->Reply(replyTo, "getWifiDirectConfigSettings", model.GetWifiDirectConfigSettings()); + + } + else if (message == "getGovernorSettings") { this->Reply(replyTo, "getGovernorSettings", model.GetGovernorSettings()); @@ -1462,10 +1485,13 @@ public: { Send("onJackServerSettingsChanged",jackServerSettings); } - virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) { Send("onWifiConfigSettingsChanged",wifiConfigSettings); } + + virtual void OnWifiDirectConfigSettingsChanged(const WifiDirectConfigSettings&wifiConfigSettings) { + Send("onWifiDirectConfigSettingsChanged",wifiConfigSettings); + } virtual void OnGovernorSettingsChanged(const std::string& governor) { Send("onGovernorSettingsChanged",governor); } diff --git a/src/PluginPreset.hpp b/src/PluginPreset.hpp index 49deeb3..ba07734 100644 --- a/src/PluginPreset.hpp +++ b/src/PluginPreset.hpp @@ -22,6 +22,7 @@ #include "json.hpp" #include "PiPedalException.hpp" #include +#include namespace pipedal { diff --git a/src/SetWifiConfig.cpp b/src/SetWifiConfig.cpp index 80a5d47..8d17e24 100644 --- a/src/SetWifiConfig.cpp +++ b/src/SetWifiConfig.cpp @@ -390,8 +390,14 @@ void UninstallP2p() restoreP2pDhcpdConfFile(); restoreP2pDnsmasqConfFile(); - sysExec(SYSTEMCTL_BIN " enable wpa_supplicant"); - sysExec(SYSTEMCTL_BIN " start wpa_supplicant"); + + sysExec(SYSTEMCTL_BIN " restart dhcpcd"); + + WifiDirectConfigSettings wifiDirectConfigSettings; + wifiDirectConfigSettings.Load(); + wifiDirectConfigSettings.enable_ = false; + wifiDirectConfigSettings.Save(); + } } @@ -408,25 +414,7 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings) else { - // ******************* pipedal_p2pd ****** - { - // ${COUNTRY_CODE} - //${PIN} - // ${DEVICE_NAME} - // ${WIFI_GROUP_FREQUENCY} - // ${INSTANCE_ID_FILE} /var/pipedal/instance_id - - std::map map; - map["COUNTRY_CODE"] = settings.countryCode_; - map["PIN"] = settings.pin_; - map["DEVICE_NAME"] = settings.hotspotName_; - map["WIFI_GROUP_FREQUENCY"] = SS(ChannelToWifiFrequency(settings.channel_)); - map["INSTANCE_ID_FILE"] = DEVICE_GUID_FILE; - - - WriteTemplateFile(map, PIPEDAL_P2PD_CONF_PATH); - - } + settings.Save(); // ******************* device_uuid DeviceIdFile deviceIdFile; @@ -436,51 +424,9 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings) // ******************** dsnmasq ****** + std::filesystem::remove(DNSMASQ_P2P_PATH); std::filesystem::copy_file(DNSMASQ_P2P_SOURCE_PATH, DNSMASQ_P2P_PATH); -#if JUNK // copy into place instaead. - std::filesystem::path dnsMasqPath(DNSMASQ_P2P_PATH); - SystemConfigFile dnsMasq; - - try - { - dnsMasq.Load(dnsMasqPath); - } - catch (const std::exception &) - { - // ignore. - } - // interface=p2p-wlan0-0 - // dhcp-range=172.24.0.3,172.24.0.127,1h - // domain=local - // address=/pipedal.local/172.24.0.1 # do this through DNS-SD? - - // except-interface=eth0 - // except-interface=wlan0 - // except-interface=lo - - - - dnsMasq.Set("interface", "p2p-wlan0-0", "Name of the Wi-Fi interface"); - dnsMasq.Set("listen-address", P2P_IP_ADDRESS); - - dnsMasq.SetDefault("dhcp-range", P2P_IP_PREFIX ".3," P2P_IP_PREFIX ".127,1h", "dhcp configuration"); - dnsMasq.SetDefault("domain", "local"); - std::string strAddress = SS("/" << settings.mdnsName_ << ".local/" P2P_IP_PREFIX << ".2"); - dnsMasq.Set("address", strAddress); - - dnsMasq.EraseLine("except-interface=eth0"); - dnsMasq.EraseLine("except-interface=wlan0"); - dnsMasq.EraseLine("except-interface=lo"); - - dnsMasq.AppendLine("except-interface=eth0"); - dnsMasq.AppendLine("except-interface=wlan0"); - dnsMasq.AppendLine("except-interface=lo"); - - dnsMasq.Save(dnsMasqPath); - -#endif - // ****** dhcpd.conf ***/ std::filesystem::path dhcpcdConfig("/etc/dhcpcd.conf"); if (std::filesystem::exists(dhcpcdConfig)) @@ -496,9 +442,9 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings) int line = dhcpcd.GetLineThatStartsWith("hostname"); std::string hostNameLine; - if (settings.mdnsName_ != "") + if (false) { - hostNameLine = "hostname " + settings.mdnsName_; + // hostNameLine = "hostname " + settings.mdnsName_; } else { @@ -559,19 +505,18 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings) sysExec(SYSTEMCTL_BIN " enable dnsmasq"); sysExec(SYSTEMCTL_BIN " restart dhcpcd"); + sysExec(SYSTEMCTL_BIN " enable dhcpcd"); sysExec(SYSTEMCTL_BIN " unmask pipedal_p2pd"); - cout << "."; cout.flush(); if (sysExec(SYSTEMCTL_BIN " restart pipedal_p2pd") != 0) { - throw PiPedalException("Unable to start the pipedal_p2pd."); + throw PiPedalException("Unable to start the Wi-Fi Direct access point."); } sysExec(SYSTEMCTL_BIN " enable pipedal_p2pd"); } - cout << "Ready." << endl; } void pipedal::OnWifiUninstall() diff --git a/src/Storage.cpp b/src/Storage.cpp index fb6afe4..9c0cc9f 100644 --- a/src/Storage.cpp +++ b/src/Storage.cpp @@ -25,6 +25,7 @@ #include #include "Lv2Log.hpp" #include +#include using namespace pipedal; @@ -167,12 +168,49 @@ void Storage::SetDataRoot(const std::filesystem::path& path) this->dataRoot = ResolveHomePath(path); } +static void CopyDirectory(const std::filesystem::path &source, const std::filesystem::path &destination) +{ + for (auto &directoryEntry: std::filesystem::directory_iterator(source)) + { + if (directoryEntry.is_regular_file()) + { + std::filesystem::path sourceFile = directoryEntry.path(); + std::filesystem::path destFile = destination / sourceFile.filename(); + + std::filesystem::copy_file(sourceFile,destFile); + chmod(destFile.c_str(),S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + + } + } +} +void Storage::MaybeCopyDefaultPresets() +{ + auto presetsDirectory = this->GetPresetsDirectory(); + + if (!std::filesystem::exists(presetsDirectory / "index.banks")) + { + CopyDirectory(this->configRoot / "default_presets" / "presets", + presetsDirectory + ); + } + + auto pluginDirectory = this->GetPluginPresetsDirectory(); + if (!std::filesystem::exists(pluginDirectory / "index.json")) + { + CopyDirectory(this->configRoot / "default_presets" / "plugin_presets", + pluginDirectory + ); + } + +} void Storage::Initialize() { try { std::filesystem::create_directories(this->GetPresetsDirectory()); std::filesystem::create_directories(this->GetPluginPresetsDirectory()); + + MaybeCopyDefaultPresets(); } catch (const std::exception &e) { @@ -189,6 +227,7 @@ void Storage::Initialize() { } LoadWifiConfigSettings(); + LoadWifiDirectConfigSettings(); LoadGovernorSettings(); } @@ -871,6 +910,21 @@ void Storage::SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSetting } this->wifiConfigSettings = copyToStore; } + +void Storage::SetWifiDirectConfigSettings(const WifiDirectConfigSettings & wifiDirectConfigSettings) +{ + WifiDirectConfigSettings copyToSave = wifiDirectConfigSettings; + copyToSave.rebootRequired_ = false; + if (!copyToSave.enable_) + { + copyToSave.pinChanged_ = false; + } + + WifiDirectConfigSettings copyToStore = wifiDirectConfigSettings; + copyToStore.pinChanged_ = false; + this->wifiDirectConfigSettings = copyToStore; +} + void Storage::LoadGovernorSettings() { std::filesystem::path path = this->dataRoot / GOVERNOR_SETTINGS_FILENAME; @@ -918,12 +972,27 @@ void Storage::LoadWifiConfigSettings() } this->wifiConfigSettings.valid_ = true; } +void Storage::LoadWifiDirectConfigSettings() +{ + + WifiDirectConfigSettings settings; + settings.enable_ = false; + settings.Load(); + settings.pinChanged_ = false; + settings.valid_ = true; + this->wifiDirectConfigSettings = settings; +} + WifiConfigSettings Storage::GetWifiConfigSettings() { return this->wifiConfigSettings; } +WifiDirectConfigSettings Storage::GetWifiDirectConfigSettings() +{ + return this->wifiDirectConfigSettings; +} void Storage::SaveCurrentPreset(const CurrentPreset ¤tPreset) diff --git a/src/Storage.hpp b/src/Storage.hpp index c77728c..dd41820 100644 --- a/src/Storage.hpp +++ b/src/Storage.hpp @@ -26,6 +26,7 @@ #include "Banks.hpp" #include "JackConfiguration.hpp" #include "WifiConfigSettings.hpp" +#include "WifiDirectConfigSettings.hpp" #include @@ -51,6 +52,7 @@ private: PluginPresetIndex pluginPresetIndex; private: + void MaybeCopyDefaultPresets(); static std::string SafeEncodeName(const std::string& name); static std::string SafeDecodeName(const std::string& name); std::filesystem::path GetPresetsDirectory() const; @@ -74,6 +76,7 @@ private: bool isJackChannelSelectionValid = false; JackChannelSelection jackChannelSelection; WifiConfigSettings wifiConfigSettings; + WifiDirectConfigSettings wifiDirectConfigSettings; std::string governorSettings = "performance"; public: Storage(); @@ -89,6 +92,7 @@ public: void LoadWifiConfigSettings(); + void LoadWifiDirectConfigSettings(); void LoadGovernorSettings(); void LoadBank(int64_t instanceId); const PedalBoard& GetCurrentPreset(); @@ -121,6 +125,10 @@ public: void SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings); WifiConfigSettings GetWifiConfigSettings(); + void SetWifiDirectConfigSettings(const WifiDirectConfigSettings & wifiDirectConfigSettings); + WifiDirectConfigSettings GetWifiDirectConfigSettings(); + + void SetGovernorSettings(const std::string & governor); std::string GetGovernorSettings() const; diff --git a/src/WifiDirectConfigSettings.cpp b/src/WifiDirectConfigSettings.cpp index bb9cb55..79f4feb 100644 --- a/src/WifiDirectConfigSettings.cpp +++ b/src/WifiDirectConfigSettings.cpp @@ -17,13 +17,17 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "pch.h" +// #include "pch.h" #include "WifiDirectConfigSettings.hpp" +#include "P2pConfigFiles.hpp" + #include "WifiConfigSettings.hpp" #include #include #include "ConfigUtil.hpp" #include "DeviceIdFile.hpp" +#include "WriteTemplateFile.hpp" +#include "ss.hpp" using namespace pipedal; @@ -34,13 +38,12 @@ JSON_MAP_BEGIN(WifiDirectConfigSettings) JSON_MAP_REFERENCE(WifiDirectConfigSettings,rebootRequired) JSON_MAP_REFERENCE(WifiDirectConfigSettings,enable) JSON_MAP_REFERENCE(WifiDirectConfigSettings,hotspotName) - JSON_MAP_REFERENCE(WifiDirectConfigSettings,hasPin) + JSON_MAP_REFERENCE(WifiDirectConfigSettings,pinChanged) JSON_MAP_REFERENCE(WifiDirectConfigSettings,pin) JSON_MAP_REFERENCE(WifiDirectConfigSettings,countryCode) JSON_MAP_REFERENCE(WifiDirectConfigSettings,channel) - JSON_MAP_REFERENCE(WifiDirectConfigSettings,mdnsName) JSON_MAP_END() - + static std::string MakePin() { std::random_device rand_dev; @@ -79,30 +82,8 @@ void WifiDirectConfigSettings::ParseArguments(const std::vector &ar if (arguments.size() == 0) { - if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","country_code",&this->countryCode_)) - { - throw invalid_argument("Default value for country code not found."); - } - if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","p2p_pin",&this->pin_)) - { - throw invalid_argument("Default value for pin not found."); - } - if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","wifiGroupFrequency",&this->channel_)) - { - throw invalid_argument("Default value for pin not found."); - } - try { - DeviceIdFile deviceIdFile; - deviceIdFile.Load(); - if (deviceIdFile.deviceName == "") - { - throw std::invalid_argument(""); - } - this->hotspotName_ = deviceIdFile.deviceName; - } catch (const std::exception &e) - { - throw std::invalid_argument("Default value for device name not found."); - } + Load(); + this->enable_ = true; } else { if (arguments.size() < 2 || arguments.size() > 4) { @@ -133,3 +114,63 @@ void WifiDirectConfigSettings::ParseArguments(const std::vector &ar throw invalid_argument("Invalid channel."); } } + + +void WifiDirectConfigSettings::Save() const +{ + // ******************* pipedal_p2pd ****** + { + // ${COUNTRY_CODE} + //${PIN} + // ${DEVICE_NAME} + // ${WIFI_GROUP_FREQUENCY} + // ${INSTANCE_ID_FILE} /var/pipedal/instance_id + + std::map map; + map["COUNTRY_CODE"] = this->countryCode_; + map["PIN"] = this->pin_; + map["DEVICE_NAME"] = ConfigUtil::QuoteString(this->hotspotName_); + map["WIFI_CHANNEL"] = SS(this->channel_); + map["ENABLED"] = this->enable_ ? "true": "false"; + map["WIFI_GROUP_FREQUENCY"] = SS(ChannelToWifiFrequency(this->channel_)); + map["INSTANCE_ID_FILE"] = DEVICE_GUID_FILE; + + + WriteTemplateFile(map, PIPEDAL_P2PD_CONF_PATH); + + } + +} +void WifiDirectConfigSettings::Load() +{ + if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","p2p_device_name",&this->hotspotName_)) + { + this->hotspotName_ = "PiPedal"; + } + + if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","country_code",&this->countryCode_)) + { + this->countryCode_ = "US"; + } + if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","p2p_pin",&this->pin_)) + { + this->pin_ = "12345678"; + } + if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","wifiChannel",&this->channel_)) + { + this->channel_ = "6"; + } + try { + DeviceIdFile deviceIdFile; + deviceIdFile.Load(); + if (deviceIdFile.deviceName == "") + { + + } + this->hotspotName_ = deviceIdFile.deviceName; + } catch (const std::exception &e) + { + } + this->valid_ = true; + +} diff --git a/src/WifiDirectConfigSettings.hpp b/src/WifiDirectConfigSettings.hpp index 5f29461..ef78f13 100644 --- a/src/WifiDirectConfigSettings.hpp +++ b/src/WifiDirectConfigSettings.hpp @@ -35,11 +35,13 @@ namespace pipedal { bool enable_ = false; std::string countryCode_ = "US"; // iso 3661 std::string hotspotName_ = "pipedal"; - std::string mdnsName_ = "pipedal"; - bool hasPin_ = false; + bool pinChanged_ = false; std::string pin_; - std::string channel_ = "g6"; + std::string channel_ = "6"; + void ParseArguments(const std::vector &arguments); + void Save() const; + void Load(); public: DECLARE_JSON_MAP(WifiDirectConfigSettings); diff --git a/src/json.hpp b/src/json.hpp index 65f55f2..c0c6de6 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -29,6 +29,7 @@ #include #include #include "PiPedalException.hpp" +#include diff --git a/src/pch.h b/src/pch.h index d7e2e6b..6b26a1e 100644 --- a/src/pch.h +++ b/src/pch.h @@ -30,12 +30,19 @@ template class TypeDisplay; #include #include #include -#include + +#include #include -#include #include #include +#include +#include +#include +#include +#ifdef JUNK + +#endif /* #include diff --git a/src/templates/pipedal_p2pd.conf.template b/src/templates/pipedal_p2pd.conf.template index 13e5be5..5c7bdb2 100644 --- a/src/templates/pipedal_p2pd.conf.template +++ b/src/templates/pipedal_p2pd.conf.template @@ -15,6 +15,11 @@ p2p_ssid_postfix=${DEVICE_NAME} # Should almost always be 2412 (ch1),2437 (ch6), or 2462 (ch11). wifiGroupFrequency=${WIFI_GROUP_FREQUENCY} +# UI use only. wifiGroupFrequency is authoritative +wifiChannel=${WIFI_CHANNEL} + +# UI use only. service state is authoritative. +enabled=${ENABLED} # P2P Device info p2p_model_name=PiPedal p2p_model_number=1 @@ -29,9 +34,6 @@ p2p_go_ht40=0 p2p_go_vht=0 p2p_go_he=0 -# Ipv4 address for the P2P group interface -p2p_ip_address=172.24.0.2/16 - # File containing the globally-unique id that identifies the service on this machine # in this format: 0a6045b0-1753-4104-b3e4-b9713b9cc356 service_guid_file=${INSTANCE_ID_FILE}