Configurable CPU Governor (fixed)
modified: .vscode/launch.json modified: react/CMakeLists.txt modified: react/public/var/config.json new file: react/src/GovernorSettings.tsx modified: react/src/JackHostStatus.tsx new file: react/src/ListSelectDialog.tsx modified: react/src/PiPedalModel.tsx modified: react/src/SettingsDialog.tsx modified: react/tmp.txt modified: src/BeastServer.cpp modified: src/BeastServer.hpp modified: src/CMakeLists.txt modified: src/ConfigMain.cpp new file: src/CpuGovernor.cpp new file: src/CpuGovernor.hpp new file: src/GovernorSettings.cpp new file: src/GovernorSettings.hpp new file: src/Ipv6Helpers.cpp new file: src/Ipv6Helpers.hpp modified: src/JackHost.cpp modified: src/PiPedalModel.cpp
This commit is contained in:
Vendored
+3
-1
@@ -47,7 +47,9 @@
|
|||||||
"/etc/pipedal/config",
|
"/etc/pipedal/config",
|
||||||
"/etc/pipedal/react",
|
"/etc/pipedal/react",
|
||||||
"-port",
|
"-port",
|
||||||
"0.0.0.0:8080"
|
"0.0.0.0:8080",
|
||||||
|
"-shutdownPort",
|
||||||
|
"3147"
|
||||||
],
|
],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
|
|||||||
+74
-75
@@ -21,88 +21,87 @@ add_custom_command(
|
|||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react
|
||||||
|
|
||||||
DEPENDS
|
DEPENDS
|
||||||
src/NumericInput.tsx
|
|
||||||
src/RenameDialog.tsx
|
|
||||||
src/ToobInputStageView.tsx
|
|
||||||
src/ToobCabSimView.tsx
|
|
||||||
src/SearchFilter.tsx
|
|
||||||
src/Draggable.tsx
|
|
||||||
src/SelectHoverBackground.tsx
|
|
||||||
src/JackStatusView.tsx
|
|
||||||
src/SplitControlView.tsx
|
|
||||||
src/MidiBindingsDialog.tsx
|
|
||||||
src/WifiChannel.tsx
|
|
||||||
src/PluginControlView.tsx
|
|
||||||
src/TemporaryDrawer.tsx
|
|
||||||
src/logo.svg
|
|
||||||
src/AlsaDeviceInfo.tsx
|
|
||||||
src/JackServerSettingsDialog.tsx
|
|
||||||
src/ZoomedUiControl.tsx
|
|
||||||
src/PedalBoardView.tsx
|
|
||||||
src/MainPage.tsx
|
|
||||||
src/App.tsx
|
|
||||||
src/AppThemed.tsx
|
|
||||||
src/PresetDialog.tsx
|
|
||||||
src/PluginPreset.tsx
|
|
||||||
src/react-app-env.d.ts
|
|
||||||
src/ToobSpectrumResponseView.tsx
|
|
||||||
src/SettingsDialog.tsx
|
|
||||||
src/SelectChannelsDialog.tsx
|
|
||||||
src/StringBuilder.tsx
|
|
||||||
src/ToobPowerStage2View.tsx
|
|
||||||
src/SearchControl.tsx
|
src/SearchControl.tsx
|
||||||
src/XxxSnippet.tsx
|
src/SplitControlView.tsx
|
||||||
src/Units.tsx
|
|
||||||
src/Jack.tsx
|
|
||||||
src/PluginControl.tsx
|
|
||||||
src/ResizeResponsiveComponent.tsx
|
|
||||||
src/Lv2Plugin.tsx
|
|
||||||
src/index.tsx
|
|
||||||
src/NoChangePassword.tsx
|
|
||||||
src/VuMeter.tsx
|
|
||||||
src/ControlViewFactory.tsx
|
|
||||||
src/JackServerSettings.tsx
|
|
||||||
src/MidiBinding.tsx
|
|
||||||
src/UploadDialog.tsx
|
|
||||||
src/PiPedalSocket.tsx
|
|
||||||
src/PedalBoard.tsx
|
|
||||||
src/JackHostStatus.tsx
|
|
||||||
src/ZoomedDial.tsx
|
|
||||||
src/Rect.tsx
|
|
||||||
src/SvgPathBuilder.tsx
|
|
||||||
src/IControlViewFactory.tsx
|
|
||||||
src/PiPedalModel.tsx
|
|
||||||
src/PluginInfoDialog.tsx
|
|
||||||
src/reportWebVitals.ts
|
|
||||||
src/PiPedalError.tsx
|
|
||||||
src/BankDialog.tsx
|
|
||||||
src/PluginIcon.tsx
|
|
||||||
src/WifiConfigDialog.tsx
|
|
||||||
src/PresetSelector.tsx
|
|
||||||
src/LoadPluginDialog.tsx
|
|
||||||
src/ToobFrequencyResponseView.tsx
|
|
||||||
src/WifiConfigSettings.tsx
|
src/WifiConfigSettings.tsx
|
||||||
src/setupTests.ts
|
|
||||||
src/AboutDialog.tsx
|
|
||||||
src/index.css
|
|
||||||
src/Banks.tsx
|
|
||||||
src/DialogEx.tsx
|
|
||||||
src/ToobWaveShapeView.tsx
|
|
||||||
src/FullScreenIME.tsx
|
src/FullScreenIME.tsx
|
||||||
src/AppThemed.css
|
src/JackHostStatus.tsx
|
||||||
|
src/SearchFilter.tsx
|
||||||
|
src/MainPage.tsx
|
||||||
|
src/PiPedalModel.tsx
|
||||||
src/PluginPresetSelector.tsx
|
src/PluginPresetSelector.tsx
|
||||||
src/Utility.tsx
|
|
||||||
src/SelectMidiChannelsDialog.tsx
|
|
||||||
src/App.test.tsx
|
|
||||||
src/MidiBindingView.tsx
|
|
||||||
src/SplitUiControls.tsx
|
|
||||||
src/PluginClass.tsx
|
|
||||||
src/ObservableProperty.tsx
|
|
||||||
src/Pedal.tsx
|
src/Pedal.tsx
|
||||||
src/GxTunerControl.tsx
|
src/ToobMLView.tsx
|
||||||
src/DraggableGrid.tsx
|
src/SettingsDialog.tsx
|
||||||
|
src/PiPedalSocket.tsx
|
||||||
|
src/ToobFrequencyResponseView.tsx
|
||||||
|
src/ControlViewFactory.tsx
|
||||||
|
src/Utility.tsx
|
||||||
src/ToobToneStackView.tsx
|
src/ToobToneStackView.tsx
|
||||||
|
src/SelectHoverBackground.tsx
|
||||||
|
src/MidiBindingsDialog.tsx
|
||||||
|
src/TemporaryDrawer.tsx
|
||||||
|
src/GxTunerView.tsx
|
||||||
|
src/ToobInputStageView.tsx
|
||||||
|
src/DraggableGrid.tsx
|
||||||
|
src/JackStatusView.tsx
|
||||||
|
src/PluginControl.tsx
|
||||||
|
src/XxxSnippet.tsx
|
||||||
|
src/PluginPreset.tsx
|
||||||
|
src/Jack.tsx
|
||||||
|
src/AlsaDeviceInfo.tsx
|
||||||
|
src/MidiBinding.tsx
|
||||||
|
src/PiPedalError.tsx
|
||||||
|
src/IControlViewFactory.tsx
|
||||||
|
src/Lv2Plugin.tsx
|
||||||
|
src/PedalBoard.tsx
|
||||||
|
src/PedalBoardView.tsx
|
||||||
|
src/PresetDialog.tsx
|
||||||
|
src/AppThemed.tsx
|
||||||
|
src/ZoomedDial.tsx
|
||||||
|
src/RenameDialog.tsx
|
||||||
|
src/SplitUiControls.tsx
|
||||||
|
src/GovernorSettings.tsx
|
||||||
|
src/AboutDialog.tsx
|
||||||
|
src/ToobSpectrumResponseView.tsx
|
||||||
|
src/PluginControlView.tsx
|
||||||
|
src/NoChangePassword.tsx
|
||||||
src/ToobSpectrumAnalyzerView.tsx
|
src/ToobSpectrumAnalyzerView.tsx
|
||||||
|
src/MidiBindingView.tsx
|
||||||
|
src/GxTunerControl.tsx
|
||||||
|
src/Banks.tsx
|
||||||
|
src/PluginPresetsDialog.tsx
|
||||||
|
src/BankDialog.tsx
|
||||||
|
src/UploadDialog.tsx
|
||||||
|
src/ToobPowerStage2View.tsx
|
||||||
|
src/index.tsx
|
||||||
|
src/Units.tsx
|
||||||
|
src/VuMeter.tsx
|
||||||
|
src/App.test.tsx
|
||||||
|
src/DialogEx.tsx
|
||||||
|
src/StringBuilder.tsx
|
||||||
|
src/SelectChannelsDialog.tsx
|
||||||
|
src/Draggable.tsx
|
||||||
|
src/ZoomedUiControl.tsx
|
||||||
|
src/Rect.tsx
|
||||||
|
src/PluginClass.tsx
|
||||||
|
src/PluginIcon.tsx
|
||||||
|
src/App.tsx
|
||||||
|
src/ResizeResponsiveComponent.tsx
|
||||||
|
src/SvgPathBuilder.tsx
|
||||||
|
src/NumericInput.tsx
|
||||||
|
src/JackServerSettings.tsx
|
||||||
|
src/ListSelectDialog.tsx
|
||||||
|
src/JackServerSettingsDialog.tsx
|
||||||
|
src/ObservableProperty.tsx
|
||||||
|
src/SelectMidiChannelsDialog.tsx
|
||||||
|
src/WifiChannel.tsx
|
||||||
|
src/LoadPluginDialog.tsx
|
||||||
|
src/WifiConfigDialog.tsx
|
||||||
|
src/PluginInfoDialog.tsx
|
||||||
|
src/ToobWaveShapeView.tsx
|
||||||
|
src/ToobCabSimView.tsx
|
||||||
|
src/PresetSelector.tsx
|
||||||
|
|
||||||
public/css/roboto.css
|
public/css/roboto.css
|
||||||
public/fonts/Roboto-BlackItalic.woff2
|
public/fonts/Roboto-BlackItalic.woff2
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"socket_server_port": 8080,
|
"socket_server_port": 8080,
|
||||||
"socket_server_address": "*",
|
"socket_server_address": "[fe80::df30:41b9:1ede:c23c]",
|
||||||
|
|
||||||
"max_upload_size": 1048576,
|
"max_upload_size": 1048576,
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) 2022 Robin 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 GovernorSettings {
|
||||||
|
deserialize(input: any) : GovernorSettings{
|
||||||
|
this.governors = input.governors;
|
||||||
|
this.governor = input.governor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
clone(): GovernorSettings
|
||||||
|
{
|
||||||
|
return new GovernorSettings().deserialize(this);
|
||||||
|
}
|
||||||
|
governors: string[] = ["ondemand","performance"];
|
||||||
|
governor: string = "performance";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -93,10 +93,10 @@ export default class JackHostStatus {
|
|||||||
{
|
{
|
||||||
(status.cpuFreqMax === status.cpuFreqMin)?
|
(status.cpuFreqMax === status.cpuFreqMin)?
|
||||||
(
|
(
|
||||||
<span> {fmtCpuFreq(status.cpuFreqMax)} {status.governor} </span>
|
<span> {status.governor} {fmtCpuFreq(status.cpuFreqMax)} </span>
|
||||||
)
|
)
|
||||||
:(
|
:(
|
||||||
<span> {fmtCpuFreq(status.cpuFreqMax)}-{fmtCpuFreq(status.cpuFreqMax)} {status.governor} </span>
|
<span> {status.governor} {fmtCpuFreq(status.cpuFreqMax)}-{fmtCpuFreq(status.cpuFreqMax)} </span>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
// Copyright (c) 2022 Robin 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 Radio from '@mui/material/Radio';
|
||||||
|
import List from '@mui/material/List';
|
||||||
|
import ListItem from '@mui/material/ListItem';
|
||||||
|
import ListItemButton from '@mui/material/ListItemButton';
|
||||||
|
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||||
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
|
|
||||||
|
import Dialog from '@mui/material/Dialog';
|
||||||
|
import DialogActions from '@mui/material/DialogActions';
|
||||||
|
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||||
|
|
||||||
|
|
||||||
|
export interface ListSelectDialogProps {
|
||||||
|
open: boolean,
|
||||||
|
title: string,
|
||||||
|
width: number,
|
||||||
|
selectedItem: string,
|
||||||
|
items: string[],
|
||||||
|
onOk: (selectedItem: string) => void,
|
||||||
|
onClose: () => void
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ListSelectDialogState {
|
||||||
|
fullScreen: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class ListSelectDialog extends ResizeResponsiveComponent<ListSelectDialogProps, ListSelectDialogState> {
|
||||||
|
|
||||||
|
refText: React.RefObject<HTMLInputElement>;
|
||||||
|
|
||||||
|
constructor(props: ListSelectDialogProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
fullScreen: false
|
||||||
|
};
|
||||||
|
this.refText = React.createRef<HTMLInputElement>();
|
||||||
|
}
|
||||||
|
mounted: boolean = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
onWindowSizeChanged(width: number, height: number): void {
|
||||||
|
this.setState({ fullScreen: height < 200 })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
super.componentDidMount();
|
||||||
|
this.mounted = true;
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
super.componentWillUnmount();
|
||||||
|
this.mounted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog onClose={()=>this.props.onClose()} open={this.props.open}>
|
||||||
|
<List sx={{pt: 0}}>
|
||||||
|
{
|
||||||
|
this.props.items.map(
|
||||||
|
(value: string, index: number) => {
|
||||||
|
return (
|
||||||
|
<ListItem key={index} >
|
||||||
|
<ListItemButton role={undefined} onClick={()=> this.props.onOk(value)} dense>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Radio
|
||||||
|
edge="start"
|
||||||
|
checked={value === this.props.selectedItem}
|
||||||
|
disableRipple
|
||||||
|
/>
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary={value} />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</List>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={()=> this.props.onClose()} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
-27
@@ -31,8 +31,9 @@ import { BankIndex } from './Banks';
|
|||||||
import JackHostStatus from './JackHostStatus';
|
import JackHostStatus from './JackHostStatus';
|
||||||
import JackServerSettings from './JackServerSettings';
|
import JackServerSettings from './JackServerSettings';
|
||||||
import MidiBinding from './MidiBinding';
|
import MidiBinding from './MidiBinding';
|
||||||
import {PluginUiPresets} from './PluginPreset';
|
import { PluginUiPresets } from './PluginPreset';
|
||||||
import WifiConfigSettings from './WifiConfigSettings';
|
import WifiConfigSettings from './WifiConfigSettings';
|
||||||
|
import GovernorSettings from './GovernorSettings';
|
||||||
import WifiChannel from './WifiChannel';
|
import WifiChannel from './WifiChannel';
|
||||||
import AlsaDeviceInfo from './AlsaDeviceInfo';
|
import AlsaDeviceInfo from './AlsaDeviceInfo';
|
||||||
|
|
||||||
@@ -316,6 +317,7 @@ export interface PiPedalModel {
|
|||||||
banks: ObservableProperty<BankIndex>;
|
banks: ObservableProperty<BankIndex>;
|
||||||
jackServerSettings: ObservableProperty<JackServerSettings>;
|
jackServerSettings: ObservableProperty<JackServerSettings>;
|
||||||
wifiConfigSettings: ObservableProperty<WifiConfigSettings>;
|
wifiConfigSettings: ObservableProperty<WifiConfigSettings>;
|
||||||
|
governorSettings: ObservableProperty<GovernorSettings>;
|
||||||
|
|
||||||
presets: ObservableProperty<PresetIndex>;
|
presets: ObservableProperty<PresetIndex>;
|
||||||
|
|
||||||
@@ -350,7 +352,7 @@ export interface PiPedalModel {
|
|||||||
saveCurrentPreset(): void;
|
saveCurrentPreset(): void;
|
||||||
saveCurrentPresetAs(newName: string): void;
|
saveCurrentPresetAs(newName: string): void;
|
||||||
|
|
||||||
saveCurrentPluginPresetAs(pluginInstanceId: number,newName: string): void;
|
saveCurrentPluginPresetAs(pluginInstanceId: number, newName: string): void;
|
||||||
|
|
||||||
loadPreset(instanceId: number): void;
|
loadPreset(instanceId: number): void;
|
||||||
updatePresets(presets: PresetIndex): Promise<void>;
|
updatePresets(presets: PresetIndex): Promise<void>;
|
||||||
@@ -397,7 +399,7 @@ export interface PiPedalModel {
|
|||||||
addControlValueChangeListener(instanceId: number, onValueChanged: ControlValueChangedHandler): ControlValueChangedHandle
|
addControlValueChangeListener(instanceId: number, onValueChanged: ControlValueChangedHandler): ControlValueChangedHandle
|
||||||
removeControlValueChangeListener(handle: ControlValueChangedHandle): void;
|
removeControlValueChangeListener(handle: ControlValueChangedHandle): void;
|
||||||
|
|
||||||
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler) : PluginPresetsChangedHandle;
|
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler): PluginPresetsChangedHandle;
|
||||||
removePluginPresetsChangedListener(handle: PluginPresetsChangedHandle): void;
|
removePluginPresetsChangedListener(handle: PluginPresetsChangedHandle): void;
|
||||||
|
|
||||||
listenForAtomOutput(instanceId: number, onComplete: (instanceId: number, atomOutput: any) => void): ListenHandle;
|
listenForAtomOutput(instanceId: number, onComplete: (instanceId: number, atomOutput: any) => void): ListenHandle;
|
||||||
@@ -405,12 +407,13 @@ export interface PiPedalModel {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
download(targetType: string, isntanceId: number|string): void;
|
download(targetType: string, isntanceId: number | string): void;
|
||||||
|
|
||||||
uploadPreset(uploadPage: string,file: File, uploadAfter: number): Promise<number>;
|
uploadPreset(uploadPage: string, file: File, uploadAfter: number): Promise<number>;
|
||||||
uploadBank(file: File, uploadAfter: number): Promise<number>;
|
uploadBank(file: File, uploadAfter: number): Promise<number>;
|
||||||
|
|
||||||
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void>;
|
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void>;
|
||||||
|
setGovernorSettings(governor: string): Promise<void>;
|
||||||
|
|
||||||
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]>;
|
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]>;
|
||||||
|
|
||||||
@@ -447,6 +450,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
= new ObservableProperty<JackServerSettings>(new JackServerSettings());
|
= new ObservableProperty<JackServerSettings>(new JackServerSettings());
|
||||||
|
|
||||||
wifiConfigSettings: ObservableProperty<WifiConfigSettings> = new ObservableProperty<WifiConfigSettings>(new WifiConfigSettings());
|
wifiConfigSettings: ObservableProperty<WifiConfigSettings> = new ObservableProperty<WifiConfigSettings>(new WifiConfigSettings());
|
||||||
|
governorSettings: ObservableProperty<GovernorSettings> = new ObservableProperty<GovernorSettings>(new GovernorSettings());
|
||||||
|
|
||||||
|
|
||||||
presets: ObservableProperty<PresetIndex> = new ObservableProperty<PresetIndex>
|
presets: ObservableProperty<PresetIndex> = new ObservableProperty<PresetIndex>
|
||||||
@@ -575,6 +579,12 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
} else if (message === "onWifiConfigSettingsChanged") {
|
} else if (message === "onWifiConfigSettingsChanged") {
|
||||||
let wifiConfigSettings = new WifiConfigSettings().deserialize(body);
|
let wifiConfigSettings = new WifiConfigSettings().deserialize(body);
|
||||||
this.wifiConfigSettings.set(wifiConfigSettings);
|
this.wifiConfigSettings.set(wifiConfigSettings);
|
||||||
|
}
|
||||||
|
else if (message === "onGovernorSettingsChanged") {
|
||||||
|
let governor = body as string;
|
||||||
|
let newSettings = this.governorSettings.get().clone();
|
||||||
|
newSettings.governor = governor;
|
||||||
|
this.governorSettings.set(newSettings);
|
||||||
} else if (message === "onBanksChanged") {
|
} else if (message === "onBanksChanged") {
|
||||||
let banks = new BankIndex().deserialize(body);
|
let banks = new BankIndex().deserialize(body);
|
||||||
this.banks.set(banks);
|
this.banks.set(banks);
|
||||||
@@ -660,6 +670,12 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data));
|
this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data));
|
||||||
|
|
||||||
|
return this.getWebSocket().request<any>("getGovernorSettings");
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
this.governorSettings.set(new GovernorSettings().deserialize(data));
|
||||||
|
|
||||||
|
|
||||||
return this.getWebSocket().request<any>("getJackServerSettings");
|
return this.getWebSocket().request<any>("getJackServerSettings");
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
@@ -792,6 +808,11 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data));
|
this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data));
|
||||||
|
|
||||||
|
return this.getWebSocket().request<any>("getGovernorSettings");
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
this.governorSettings.set(new GovernorSettings().deserialize(data));
|
||||||
|
|
||||||
|
|
||||||
return this.getWebSocket().request<any>("getJackServerSettings");
|
return this.getWebSocket().request<any>("getJackServerSettings");
|
||||||
})
|
})
|
||||||
@@ -994,7 +1015,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
|
|
||||||
_pluginPresetsChangedHandles: PluginPresetsChangedHandle[] = [];
|
_pluginPresetsChangedHandles: PluginPresetsChangedHandle[] = [];
|
||||||
|
|
||||||
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler) : PluginPresetsChangedHandle {
|
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler): PluginPresetsChangedHandle {
|
||||||
let handle = ++this.nextListenHandle;
|
let handle = ++this.nextListenHandle;
|
||||||
let t: PluginPresetsChangedHandle = {
|
let t: PluginPresetsChangedHandle = {
|
||||||
_id: handle,
|
_id: handle,
|
||||||
@@ -1003,25 +1024,20 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
this._pluginPresetsChangedHandles.push(t);
|
this._pluginPresetsChangedHandles.push(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
removePluginPresetsChangedListener(handle: PluginPresetsChangedHandle): void
|
removePluginPresetsChangedListener(handle: PluginPresetsChangedHandle): void {
|
||||||
{
|
|
||||||
let pos = -1;
|
let pos = -1;
|
||||||
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i)
|
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i) {
|
||||||
{
|
if (this._pluginPresetsChangedHandles[i]._id === handle._id) {
|
||||||
if (this._pluginPresetsChangedHandles[i]._id === handle._id)
|
|
||||||
{
|
|
||||||
pos = i;
|
pos = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pos !== -1)
|
if (pos !== -1) {
|
||||||
{
|
this._pluginPresetsChangedHandles.splice(pos, 1);
|
||||||
this._pluginPresetsChangedHandles.splice(pos,1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
firePluginPresetsChanged(pluginUri: string): void {
|
firePluginPresetsChanged(pluginUri: string): void {
|
||||||
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i)
|
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i) {
|
||||||
{
|
|
||||||
this._pluginPresetsChangedHandles[i]._handler(pluginUri);
|
this._pluginPresetsChangedHandles[i]._handler(pluginUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1298,7 +1314,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
saveCurrentPluginPresetAs(pluginInstanceId: number,newName: string): Promise<number> {
|
saveCurrentPluginPresetAs(pluginInstanceId: number, newName: string): Promise<number> {
|
||||||
// default behaviour is to save after the currently selected preset.
|
// default behaviour is to save after the currently selected preset.
|
||||||
let request: any = {
|
let request: any = {
|
||||||
instanceId: pluginInstanceId,
|
instanceId: pluginInstanceId,
|
||||||
@@ -1567,22 +1583,21 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
this.webSocket?.send("loadPluginPreset", { pluginInstanceId: pluginInstanceId, presetInstanceId: presetInstanceId });
|
this.webSocket?.send("loadPluginPreset", { pluginInstanceId: pluginInstanceId, presetInstanceId: presetInstanceId });
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePluginPresetsChanged(pluginUri: string):void {
|
handlePluginPresetsChanged(pluginUri: string): void {
|
||||||
this.uncachePluginPreset(pluginUri);
|
this.uncachePluginPreset(pluginUri);
|
||||||
this.firePluginPresetsChanged(pluginUri);
|
this.firePluginPresetsChanged(pluginUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
updatePluginPresets(pluginUri: string, presets: PluginUiPresets): Promise<void>
|
updatePluginPresets(pluginUri: string, presets: PluginUiPresets): Promise<void> {
|
||||||
{
|
|
||||||
this.presetCache[pluginUri] = presets;
|
this.presetCache[pluginUri] = presets;
|
||||||
this.firePluginPresetsChanged(pluginUri);
|
this.firePluginPresetsChanged(pluginUri);
|
||||||
return nullCast(this.webSocket).request<void>("updatePluginPresets", presets);
|
return nullCast(this.webSocket).request<void>("updatePluginPresets", presets);
|
||||||
}
|
}
|
||||||
duplicatePluginPreset(pluginUri: string, instanceId: number): Promise<number>
|
duplicatePluginPreset(pluginUri: string, instanceId: number): Promise<number> {
|
||||||
{
|
|
||||||
return nullCast(this.webSocket).request<number>("copyPluginPreset", {
|
return nullCast(this.webSocket).request<number>("copyPluginPreset", {
|
||||||
pluginUri: pluginUri, instanceId: instanceId });
|
pluginUri: pluginUri, instanceId: instanceId
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1692,7 +1707,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
window.open(url, "_blank");
|
window.open(url, "_blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadPreset(uploadPage: string,file: File, uploadAfter: number): Promise<number> {
|
uploadPreset(uploadPage: string, file: File, uploadAfter: number): Promise<number> {
|
||||||
let result = new Promise<number>((resolve, reject) => {
|
let result = new Promise<number>((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
if (file.size > this.maxUploadSize) {
|
if (file.size > this.maxUploadSize) {
|
||||||
@@ -1775,6 +1790,27 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
setGovernorSettings(governor: string): Promise<void> {
|
||||||
|
let newSettings = this.governorSettings.get().clone();
|
||||||
|
newSettings.governor = governor;
|
||||||
|
this.governorSettings.set(newSettings);
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
|
||||||
|
let ws = this.webSocket;
|
||||||
|
if (!ws) return;
|
||||||
|
ws.request<void>(
|
||||||
|
"setGovernorSettings",
|
||||||
|
governor
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void> {
|
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void> {
|
||||||
let result = new Promise<void>((resolve, reject) => {
|
let result = new Promise<void>((resolve, reject) => {
|
||||||
let oldSettings = this.wifiConfigSettings.get();
|
let oldSettings = this.wifiConfigSettings.get();
|
||||||
@@ -1866,8 +1902,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
|
|
||||||
preloadImages(imageList: string): void {
|
preloadImages(imageList: string): void {
|
||||||
let imageNames = imageList.split(';');
|
let imageNames = imageList.split(';');
|
||||||
for (let i = 0; i < imageNames.length; ++i)
|
for (let i = 0; i < imageNames.length; ++i) {
|
||||||
{
|
|
||||||
let imageName = imageNames[i];
|
let imageName = imageNames[i];
|
||||||
let img = new Image();
|
let img = new Image();
|
||||||
img.src = "/img/" + imageName;
|
img.src = "/img/" + imageName;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
import React, { SyntheticEvent, Component } from 'react';
|
import React, { SyntheticEvent, Component } from 'react';
|
||||||
|
import ListSelectDialog from './ListSelectDialog';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel';
|
import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel';
|
||||||
@@ -36,6 +37,7 @@ import JackHostStatus from './JackHostStatus';
|
|||||||
import WifiConfigSettings from './WifiConfigSettings';
|
import WifiConfigSettings from './WifiConfigSettings';
|
||||||
import WifiConfigDialog from './WifiConfigDialog';
|
import WifiConfigDialog from './WifiConfigDialog';
|
||||||
import DialogEx from './DialogEx'
|
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 { createStyles, Theme } from '@mui/material/styles';
|
||||||
@@ -55,10 +57,12 @@ interface SettingsDialogState {
|
|||||||
jackSettings: JackChannelSelection;
|
jackSettings: JackChannelSelection;
|
||||||
jackServerSettings: JackServerSettings;
|
jackServerSettings: JackServerSettings;
|
||||||
jackStatus?: JackHostStatus;
|
jackStatus?: JackHostStatus;
|
||||||
|
governorSettings: GovernorSettings;
|
||||||
|
|
||||||
wifiConfigSettings: WifiConfigSettings;
|
wifiConfigSettings: WifiConfigSettings;
|
||||||
|
|
||||||
showWifiConfigDialog: boolean;
|
showWifiConfigDialog: boolean;
|
||||||
|
showGovernorSettingsDialog: boolean;
|
||||||
showInputSelectDialog: boolean;
|
showInputSelectDialog: boolean;
|
||||||
showOutputSelectDialog: boolean;
|
showOutputSelectDialog: boolean;
|
||||||
showMidiSelectDialog: boolean;
|
showMidiSelectDialog: boolean;
|
||||||
@@ -146,7 +150,9 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
jackStatus: undefined,
|
jackStatus: undefined,
|
||||||
jackSettings: this.model.jackSettings.get(),
|
jackSettings: this.model.jackSettings.get(),
|
||||||
wifiConfigSettings: this.model.wifiConfigSettings.get(),
|
wifiConfigSettings: this.model.wifiConfigSettings.get(),
|
||||||
|
governorSettings: this.model.governorSettings.get(),
|
||||||
showWifiConfigDialog: false,
|
showWifiConfigDialog: false,
|
||||||
|
showGovernorSettingsDialog: false,
|
||||||
showInputSelectDialog: false,
|
showInputSelectDialog: false,
|
||||||
showOutputSelectDialog: false,
|
showOutputSelectDialog: false,
|
||||||
showMidiSelectDialog: false,
|
showMidiSelectDialog: false,
|
||||||
@@ -160,6 +166,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
this.handleJackSettingsChanged = this.handleJackSettingsChanged.bind(this);
|
this.handleJackSettingsChanged = this.handleJackSettingsChanged.bind(this);
|
||||||
this.handleJackServerSettingsChanged = this.handleJackServerSettingsChanged.bind(this);
|
this.handleJackServerSettingsChanged = this.handleJackServerSettingsChanged.bind(this);
|
||||||
this.handleWifiConfigSettingsChanged = this.handleWifiConfigSettingsChanged.bind(this);
|
this.handleWifiConfigSettingsChanged = this.handleWifiConfigSettingsChanged.bind(this);
|
||||||
|
this.handleGovernorSettingsChanged = this.handleGovernorSettingsChanged.bind(this);
|
||||||
this.handleConnectionStateChanged = this.handleConnectionStateChanged.bind(this);
|
this.handleConnectionStateChanged = this.handleConnectionStateChanged.bind(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -182,6 +189,15 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
this.model.showAlert(err);
|
this.model.showAlert(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
handleApplyGovernorSettings(governor: string): void {
|
||||||
|
this.model.setGovernorSettings(governor)
|
||||||
|
.then(() => {
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.model.showAlert(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
handleWifiConfigSettingsChanged(): void {
|
handleWifiConfigSettingsChanged(): void {
|
||||||
this.setState(
|
this.setState(
|
||||||
@@ -190,6 +206,14 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
handleGovernorSettingsChanged(): void {
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
governorSettings: this.model.governorSettings.get()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
handleJackSettingsChanged(): void {
|
handleJackSettingsChanged(): void {
|
||||||
this.setState({
|
this.setState({
|
||||||
jackSettings: this.model.jackSettings.get()
|
jackSettings: this.model.jackSettings.get()
|
||||||
@@ -233,6 +257,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
this.model.jackConfiguration.addOnChangedHandler(this.handleJackConfigurationChanged);
|
this.model.jackConfiguration.addOnChangedHandler(this.handleJackConfigurationChanged);
|
||||||
this.model.jackServerSettings.addOnChangedHandler(this.handleJackServerSettingsChanged);
|
this.model.jackServerSettings.addOnChangedHandler(this.handleJackServerSettingsChanged);
|
||||||
this.model.wifiConfigSettings.addOnChangedHandler(this.handleWifiConfigSettingsChanged);
|
this.model.wifiConfigSettings.addOnChangedHandler(this.handleWifiConfigSettingsChanged);
|
||||||
|
this.model.governorSettings.addOnChangedHandler(this.handleGovernorSettingsChanged);
|
||||||
this.model.getJackStatus()
|
this.model.getJackStatus()
|
||||||
.then((jackStatus) =>
|
.then((jackStatus) =>
|
||||||
this.setState(
|
this.setState(
|
||||||
@@ -261,6 +286,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
this.model.jackSettings.removeOnChangedHandler(this.handleJackSettingsChanged);
|
this.model.jackSettings.removeOnChangedHandler(this.handleJackSettingsChanged);
|
||||||
this.model.jackServerSettings.removeOnChangedHandler(this.handleJackServerSettingsChanged);
|
this.model.jackServerSettings.removeOnChangedHandler(this.handleJackServerSettingsChanged);
|
||||||
this.model.wifiConfigSettings.removeOnChangedHandler(this.handleWifiConfigSettingsChanged);
|
this.model.wifiConfigSettings.removeOnChangedHandler(this.handleWifiConfigSettingsChanged);
|
||||||
|
this.model.wifiConfigSettings.removeOnChangedHandler(this.handleGovernorSettingsChanged);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,6 +340,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
let newSelection = this.state.jackSettings.clone();
|
let newSelection = this.state.jackSettings.clone();
|
||||||
newSelection.inputMidiPorts = channels;
|
newSelection.inputMidiPorts = channels;
|
||||||
this.model.setJackSettings(newSelection);
|
this.model.setJackSettings(newSelection);
|
||||||
|
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
showMidiSelectDialog: false,
|
showMidiSelectDialog: false,
|
||||||
@@ -358,6 +385,11 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
showWifiConfigDialog: true
|
showWifiConfigDialog: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
handleShowGovernorSettingsDialogDialog() {
|
||||||
|
this.setState({
|
||||||
|
showGovernorSettingsDialog: true
|
||||||
|
});
|
||||||
|
}
|
||||||
handleRestart() {
|
handleRestart() {
|
||||||
this.setState({ restarting: true });
|
this.setState({ restarting: true });
|
||||||
this.model.restart()
|
this.model.restart()
|
||||||
@@ -417,19 +449,19 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
>
|
>
|
||||||
<div >
|
<div >
|
||||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
|
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
|
||||||
AUDIO
|
STATUS
|
||||||
</Typography>
|
</Typography>
|
||||||
{(!isConfigValid) ?
|
{(!isConfigValid) ?
|
||||||
(
|
(
|
||||||
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
|
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
|
||||||
<Typography display="block" variant="caption" color="textSecondary">Status: <span style={{ color: "#F00" }}>Not configured.</span></Typography>
|
<Typography display="block" variant="caption" color="textSecondary">Status: <span style={{ color: "#F00" }}>Not configured.</span></Typography>
|
||||||
<Typography display="block" variant="caption" color="textSecondary">CPU: </Typography>
|
<Typography display="block" variant="caption" color="textSecondary">Governor: </Typography>
|
||||||
</div>
|
</div>
|
||||||
) :
|
) :
|
||||||
(
|
(
|
||||||
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
|
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
|
||||||
{JackHostStatus.getDisplayView("Status:\u00A0", this.state.jackStatus)}
|
{JackHostStatus.getDisplayView("", this.state.jackStatus)}
|
||||||
{JackHostStatus.getCpuInfo("CPU:\u00A0", this.state.jackStatus)}
|
{ JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -442,6 +474,9 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
|
||||||
|
AUDIO
|
||||||
|
</Typography>
|
||||||
<ButtonBase className={classes.setting} onClick={() => this.handleJackServerSettings()}
|
<ButtonBase className={classes.setting} onClick={() => this.handleJackServerSettings()}
|
||||||
>
|
>
|
||||||
<SelectHoverBackground selected={false} showHover={true} />
|
<SelectHoverBackground selected={false} showHover={true} />
|
||||||
@@ -512,6 +547,18 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
<ButtonBase className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
||||||
|
onClick={() => this.handleShowGovernorSettingsDialogDialog()} >
|
||||||
|
<SelectHoverBackground selected={false} showHover={true} />
|
||||||
|
<div style={{ width: "100%" }}>
|
||||||
|
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||||
|
CPU Governor</Typography>
|
||||||
|
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
||||||
|
{this.state.governorSettings.governor }
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ButtonBase>
|
||||||
<ButtonBase className={classes.setting} disabled={!isConfigValid || disableShutdown}
|
<ButtonBase className={classes.setting} disabled={!isConfigValid || disableShutdown}
|
||||||
onClick={() => this.handleRestart()} >
|
onClick={() => this.handleRestart()} >
|
||||||
<SelectHoverBackground selected={false} showHover={true} />
|
<SelectHoverBackground selected={false} showHover={true} />
|
||||||
@@ -556,6 +603,32 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
(this.state.showGovernorSettingsDialog) &&
|
||||||
|
(
|
||||||
|
<ListSelectDialog
|
||||||
|
width={220}
|
||||||
|
open={this.state.showGovernorSettingsDialog}
|
||||||
|
items={this.state.governorSettings.governors}
|
||||||
|
selectedItem={this.state.governorSettings.governor}
|
||||||
|
title="Governor"
|
||||||
|
onClose={()=> this.setState({showGovernorSettingsDialog: false})}
|
||||||
|
onOk={(selectedValue) => {
|
||||||
|
this.model.setGovernorSettings(selectedValue)
|
||||||
|
.then(()=>{
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.model.showAlert(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({showGovernorSettingsDialog: false})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
</ListSelectDialog>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
{
|
{
|
||||||
(this.state.showMidiSelectDialog) &&
|
(this.state.showMidiSelectDialog) &&
|
||||||
(
|
(
|
||||||
|
|||||||
+74
-76
@@ -1,83 +1,81 @@
|
|||||||
src
|
|
||||||
src/NumericInput.tsx
|
|
||||||
src/RenameDialog.tsx
|
|
||||||
src/ToobInputStageView.tsx
|
|
||||||
src/ToobCabSimView.tsx
|
|
||||||
src/SearchFilter.tsx
|
|
||||||
src/Draggable.tsx
|
|
||||||
src/SelectHoverBackground.tsx
|
|
||||||
src/JackStatusView.tsx
|
|
||||||
src/SplitControlView.tsx
|
|
||||||
src/MidiBindingsDialog.tsx
|
|
||||||
src/WifiChannel.tsx
|
|
||||||
src/PluginControlView.tsx
|
|
||||||
src/TemporaryDrawer.tsx
|
|
||||||
src/LoadPluginDialogBackup.tsx
|
|
||||||
src/logo.svg
|
|
||||||
src/AlsaDeviceInfo.tsx
|
|
||||||
src/JackServerSettingsDialog.tsx
|
|
||||||
src/ZoomedUiControl.tsx
|
|
||||||
src/PedalBoardView.tsx
|
|
||||||
src/MainPage.tsx
|
|
||||||
src/App.tsx
|
|
||||||
src/PresetDialog.tsx
|
|
||||||
src/PluginPreset.tsx
|
|
||||||
src/react-app-env.d.ts
|
|
||||||
src/ToobSpectrumResponseView.tsx
|
|
||||||
src/SettingsDialog.tsx
|
|
||||||
src/SelectChannelsDialog.tsx
|
|
||||||
src/StringBuilder.tsx
|
|
||||||
src/ToobPowerStage2View.tsx
|
|
||||||
src/SearchControl.tsx
|
src/SearchControl.tsx
|
||||||
src/XxxSnippet.tsx
|
src/SplitControlView.tsx
|
||||||
src/Units.tsx
|
|
||||||
src/Jack.tsx
|
|
||||||
src/PluginControl.tsx
|
|
||||||
src/ResizeResponsiveComponent.tsx
|
|
||||||
src/Lv2Plugin.tsx
|
|
||||||
src/index.tsx
|
|
||||||
src/NoChangePassword.tsx
|
|
||||||
src/VuMeter.tsx
|
|
||||||
src/ControlViewFactory.tsx
|
|
||||||
src/JackServerSettings.tsx
|
|
||||||
src/MidiBinding.tsx
|
|
||||||
src/UploadDialog.tsx
|
|
||||||
src/PiPedalSocket.tsx
|
|
||||||
src/PedalBoard.tsx
|
|
||||||
src/JackHostStatus.tsx
|
|
||||||
src/ZoomedDial.tsx
|
|
||||||
src/Rect.tsx
|
|
||||||
src/SvgPathBuilder.tsx
|
|
||||||
src/IControlViewFactory.tsx
|
|
||||||
src/PiPedalModel.tsx
|
|
||||||
src/PluginInfoDialog.tsx
|
|
||||||
src/reportWebVitals.ts
|
|
||||||
src/PiPedalError.tsx
|
|
||||||
src/BankDialog.tsx
|
|
||||||
src/PluginIcon.tsx
|
|
||||||
src/WifiConfigDialog.tsx
|
|
||||||
src/PresetSelector.tsx
|
|
||||||
src/LoadPluginDialog.tsx
|
|
||||||
src/ToobFrequencyResponseView.tsx
|
|
||||||
src/WifiConfigSettings.tsx
|
src/WifiConfigSettings.tsx
|
||||||
src/setupTests.ts
|
|
||||||
src/AboutDialog.tsx
|
|
||||||
src/index.css
|
|
||||||
src/Banks.tsx
|
|
||||||
src/DialogEx.tsx
|
|
||||||
src/ToobWaveShapeView.tsx
|
|
||||||
src/FullScreenIME.tsx
|
src/FullScreenIME.tsx
|
||||||
src/App.css
|
src/JackHostStatus.tsx
|
||||||
|
src/SearchFilter.tsx
|
||||||
|
src/MainPage.tsx
|
||||||
|
src/PiPedalModel.tsx
|
||||||
src/PluginPresetSelector.tsx
|
src/PluginPresetSelector.tsx
|
||||||
src/Utility.tsx
|
|
||||||
src/SelectMidiChannelsDialog.tsx
|
|
||||||
src/App.test.tsx
|
|
||||||
src/MidiBindingView.tsx
|
|
||||||
src/SplitUiControls.tsx
|
|
||||||
src/PluginClass.tsx
|
|
||||||
src/ObservableProperty.tsx
|
|
||||||
src/Pedal.tsx
|
src/Pedal.tsx
|
||||||
src/GxTunerControl.tsx
|
src/ToobMLView.tsx
|
||||||
src/DraggableGrid.tsx
|
src/SettingsDialog.tsx
|
||||||
|
src/PiPedalSocket.tsx
|
||||||
|
src/ToobFrequencyResponseView.tsx
|
||||||
|
src/ControlViewFactory.tsx
|
||||||
|
src/Utility.tsx
|
||||||
src/ToobToneStackView.tsx
|
src/ToobToneStackView.tsx
|
||||||
|
src/SelectHoverBackground.tsx
|
||||||
|
src/MidiBindingsDialog.tsx
|
||||||
|
src/TemporaryDrawer.tsx
|
||||||
|
src/GxTunerView.tsx
|
||||||
|
src/ToobInputStageView.tsx
|
||||||
|
src/DraggableGrid.tsx
|
||||||
|
src/JackStatusView.tsx
|
||||||
|
src/PluginControl.tsx
|
||||||
|
src/XxxSnippet.tsx
|
||||||
|
src/PluginPreset.tsx
|
||||||
|
src/Jack.tsx
|
||||||
|
src/AlsaDeviceInfo.tsx
|
||||||
|
src/MidiBinding.tsx
|
||||||
|
src/PiPedalError.tsx
|
||||||
|
src/IControlViewFactory.tsx
|
||||||
|
src/Lv2Plugin.tsx
|
||||||
|
src/PedalBoard.tsx
|
||||||
|
src/PedalBoardView.tsx
|
||||||
|
src/PresetDialog.tsx
|
||||||
|
src/AppThemed.tsx
|
||||||
|
src/ZoomedDial.tsx
|
||||||
|
src/RenameDialog.tsx
|
||||||
|
src/SplitUiControls.tsx
|
||||||
|
src/GovernorSettings.tsx
|
||||||
|
src/AboutDialog.tsx
|
||||||
|
src/ToobSpectrumResponseView.tsx
|
||||||
|
src/PluginControlView.tsx
|
||||||
|
src/NoChangePassword.tsx
|
||||||
src/ToobSpectrumAnalyzerView.tsx
|
src/ToobSpectrumAnalyzerView.tsx
|
||||||
|
src/MidiBindingView.tsx
|
||||||
|
src/GxTunerControl.tsx
|
||||||
|
src/Banks.tsx
|
||||||
|
src/PluginPresetsDialog.tsx
|
||||||
|
src/BankDialog.tsx
|
||||||
|
src/UploadDialog.tsx
|
||||||
|
src/ToobPowerStage2View.tsx
|
||||||
|
src/index.tsx
|
||||||
|
src/Units.tsx
|
||||||
|
src/VuMeter.tsx
|
||||||
|
src/App.test.tsx
|
||||||
|
src/DialogEx.tsx
|
||||||
|
src/StringBuilder.tsx
|
||||||
|
src/SelectChannelsDialog.tsx
|
||||||
|
src/Draggable.tsx
|
||||||
|
src/ZoomedUiControl.tsx
|
||||||
|
src/Rect.tsx
|
||||||
|
src/PluginClass.tsx
|
||||||
|
src/PluginIcon.tsx
|
||||||
|
src/App.tsx
|
||||||
|
src/ResizeResponsiveComponent.tsx
|
||||||
|
src/SvgPathBuilder.tsx
|
||||||
|
src/NumericInput.tsx
|
||||||
|
src/JackServerSettings.tsx
|
||||||
|
src/ListSelectDialog.tsx
|
||||||
|
src/JackServerSettingsDialog.tsx
|
||||||
|
src/ObservableProperty.tsx
|
||||||
|
src/SelectMidiChannelsDialog.tsx
|
||||||
|
src/WifiChannel.tsx
|
||||||
|
src/LoadPluginDialog.tsx
|
||||||
|
src/WifiConfigDialog.tsx
|
||||||
|
src/PluginInfoDialog.tsx
|
||||||
|
src/ToobWaveShapeView.tsx
|
||||||
|
src/ToobCabSimView.tsx
|
||||||
|
src/PresetSelector.tsx
|
||||||
|
|||||||
+57
-6
@@ -49,6 +49,40 @@ pipedal::last_modified(const std::filesystem::path &path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string getHostName()
|
||||||
|
{
|
||||||
|
char buff[512];
|
||||||
|
if (gethostname(buff,sizeof(buff)) == 0)
|
||||||
|
{
|
||||||
|
buff[511] = '\0';
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getIpv4Address(const std::string interface)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
struct ifreq ifr;
|
||||||
|
memset(&ifr,0,sizeof(ifr));
|
||||||
|
|
||||||
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
/* I want to get an IPv4 IP address */
|
||||||
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
|
|
||||||
|
/* I want an IP address attached to "eth0" */
|
||||||
|
strncpy(ifr.ifr_name, interface.c_str(), IFNAMSIZ-1);
|
||||||
|
|
||||||
|
int result = ioctl(fd, SIOCGIFADDR, &ifr);
|
||||||
|
if (result == -1) return "";
|
||||||
|
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
char *name = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
|
||||||
|
if (name == nullptr) return "";
|
||||||
|
return name;
|
||||||
|
}
|
||||||
static std::map<std::string, std::string> extensionsToMimeType = {
|
static std::map<std::string, std::string> extensionsToMimeType = {
|
||||||
{".htm", "text/html; charset=UTF-8"},
|
{".htm", "text/html; charset=UTF-8"},
|
||||||
{".html", "text/html; charset=UTF-8"},
|
{".html", "text/html; charset=UTF-8"},
|
||||||
@@ -192,7 +226,8 @@ namespace pipedal
|
|||||||
webSocket(webSocket)
|
webSocket(webSocket)
|
||||||
{
|
{
|
||||||
uri requestUri(webSocket->get_uri()->str().c_str());
|
uri requestUri(webSocket->get_uri()->str().c_str());
|
||||||
fromAddress = requestUri.authority();
|
fromAddress = SS(webSocket->get_socket().remote_endpoint());
|
||||||
|
|
||||||
|
|
||||||
auto pFactory = pServer->GetSocketFactory(requestUri);
|
auto pFactory = pServer->GetSocketFactory(requestUri);
|
||||||
if (!pFactory)
|
if (!pFactory)
|
||||||
@@ -364,11 +399,14 @@ namespace pipedal
|
|||||||
con->set_status(websocketpp::http::status_code::ok);
|
con->set_status(websocketpp::http::status_code::ok);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto requestHandler : this->request_handlers)
|
for (auto requestHandler : this->request_handlers)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (requestHandler->wants(req.method(), requestUri))
|
if (requestHandler->wants(req.method(), requestUri))
|
||||||
{
|
{
|
||||||
|
std::string fromAddress = SS(con->get_remote_endpoint());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (req.method() == HttpVerb::head)
|
if (req.method() == HttpVerb::head)
|
||||||
@@ -377,7 +415,7 @@ namespace pipedal
|
|||||||
res.set(HttpField::date, HtmlHelper::timeToHttpDate(time(nullptr)));
|
res.set(HttpField::date, HtmlHelper::timeToHttpDate(time(nullptr)));
|
||||||
res.set(HttpField::access_control_allow_origin, origin);
|
res.set(HttpField::access_control_allow_origin, origin);
|
||||||
|
|
||||||
requestHandler->head_response(requestUri, req, res, ec);
|
requestHandler->head_response(fromAddress,requestUri, req, res, ec);
|
||||||
res.keepAlive(req.keepAlive());
|
res.keepAlive(req.keepAlive());
|
||||||
if (ec == std::errc::no_such_file_or_directory)
|
if (ec == std::errc::no_such_file_or_directory)
|
||||||
{
|
{
|
||||||
@@ -401,7 +439,7 @@ namespace pipedal
|
|||||||
|
|
||||||
res.set(HttpField::cache_control, "max-age: 31104000"); // cache for a year.
|
res.set(HttpField::cache_control, "max-age: 31104000"); // cache for a year.
|
||||||
|
|
||||||
requestHandler->get_response(requestUri, req, res, ec);
|
requestHandler->get_response(fromAddress,requestUri, req, res, ec);
|
||||||
res.keepAlive(req.keepAlive());
|
res.keepAlive(req.keepAlive());
|
||||||
|
|
||||||
if (ec == std::errc::no_such_file_or_directory)
|
if (ec == std::errc::no_such_file_or_directory)
|
||||||
@@ -425,7 +463,7 @@ namespace pipedal
|
|||||||
res.set(HttpField::date, HtmlHelper::timeToHttpDate(time(nullptr)));
|
res.set(HttpField::date, HtmlHelper::timeToHttpDate(time(nullptr)));
|
||||||
res.set(HttpField::access_control_allow_origin, origin);
|
res.set(HttpField::access_control_allow_origin, origin);
|
||||||
|
|
||||||
requestHandler->post_response(requestUri, req, res, ec);
|
requestHandler->post_response(fromAddress,requestUri, req, res, ec);
|
||||||
|
|
||||||
if (ec == std::errc::no_such_file_or_directory)
|
if (ec == std::errc::no_such_file_or_directory)
|
||||||
{
|
{
|
||||||
@@ -547,15 +585,28 @@ namespace pipedal
|
|||||||
m_endpoint.set_close_handler(bind(&BeastServerImpl::on_close, this, _1));
|
m_endpoint.set_close_handler(bind(&BeastServerImpl::on_close, this, _1));
|
||||||
m_endpoint.set_http_handler(bind(&BeastServerImpl::on_http, this, _1));
|
m_endpoint.set_http_handler(bind(&BeastServerImpl::on_http, this, _1));
|
||||||
|
|
||||||
|
std::string hostName = getHostName();
|
||||||
|
if (hostName.length() != 0)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Listening on " << this->address << ":" << this->port;
|
ss << "Listening on " << hostName << ".local:" << this->port;
|
||||||
Lv2Log::info(ss.str());
|
Lv2Log::info(ss.str());
|
||||||
}
|
}
|
||||||
|
std::string ipv4Address = getIpv4Address("eth0");
|
||||||
|
if (ipv4Address.length() != 0)
|
||||||
|
{
|
||||||
|
Lv2Log::info(SS("Listening on " << ipv4Address << ":" << this->port));
|
||||||
|
}
|
||||||
|
std::string wifiAddress = getIpv4Address("wlan0");
|
||||||
|
if (wifiAddress.length() != 0)
|
||||||
|
{
|
||||||
|
Lv2Log::info(SS("Listening on Wi-Fi address " << wifiAddress << ":" << this->port));
|
||||||
|
}
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << port;
|
ss << port;
|
||||||
m_endpoint.listen(this->address, ss.str());
|
// m_endpoint.listen(this->address, ss.str());
|
||||||
|
m_endpoint.listen(tcp::v6(),(uint16_t)port);
|
||||||
m_endpoint.start_accept();
|
m_endpoint.start_accept();
|
||||||
|
|
||||||
// Start IOC service threads.
|
// Start IOC service threads.
|
||||||
|
|||||||
+34
-1
@@ -3,7 +3,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
#include <boost/asio/ip/network_v4.hpp>
|
#include <boost/asio/ip/network_v6.hpp>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
@@ -164,12 +164,34 @@ public:
|
|||||||
HttpResponse &res,
|
HttpResponse &res,
|
||||||
std::error_code &ec) = 0;
|
std::error_code &ec) = 0;
|
||||||
|
|
||||||
|
virtual void head_response(
|
||||||
|
const std::string&fromAddress,
|
||||||
|
const uri&request_uri,
|
||||||
|
const HttpRequest &req,
|
||||||
|
HttpResponse &res,
|
||||||
|
std::error_code &ec) {
|
||||||
|
head_response(request_uri,req,res,ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual void get_response(
|
virtual void get_response(
|
||||||
const uri&request_uri,
|
const uri&request_uri,
|
||||||
const HttpRequest &req,
|
const HttpRequest &req,
|
||||||
HttpResponse &res,
|
HttpResponse &res,
|
||||||
std::error_code &ec) = 0;
|
std::error_code &ec) = 0;
|
||||||
|
|
||||||
|
virtual void get_response(
|
||||||
|
const std::string&fromAddress,
|
||||||
|
const uri&request_uri,
|
||||||
|
const HttpRequest &req,
|
||||||
|
HttpResponse &res,
|
||||||
|
std::error_code &ec)
|
||||||
|
{
|
||||||
|
get_response(request_uri,req,res,ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void post_response(
|
virtual void post_response(
|
||||||
const uri&request_uri,
|
const uri&request_uri,
|
||||||
const HttpRequest &req,
|
const HttpRequest &req,
|
||||||
@@ -178,6 +200,17 @@ public:
|
|||||||
{
|
{
|
||||||
get_response(request_uri,req,res,ec);
|
get_response(request_uri,req,res,ec);
|
||||||
}
|
}
|
||||||
|
virtual void post_response(
|
||||||
|
const std::string&fromAddress,
|
||||||
|
const uri&request_uri,
|
||||||
|
const HttpRequest &req,
|
||||||
|
HttpResponse &res,
|
||||||
|
std::error_code &ec)
|
||||||
|
{
|
||||||
|
post_response(
|
||||||
|
request_uri,req,res,ec);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BeastServer {
|
class BeastServer {
|
||||||
|
|||||||
@@ -102,7 +102,10 @@ add_custom_command(
|
|||||||
|
|
||||||
|
|
||||||
set (PIPEDAL_SOURCES
|
set (PIPEDAL_SOURCES
|
||||||
|
Ipv6Helpers.cpp Ipv6Helpers.hpp
|
||||||
PluginPreset.cpp PluginPreset.hpp
|
PluginPreset.cpp PluginPreset.hpp
|
||||||
|
CpuGovernor.cpp CpuGovernor.hpp
|
||||||
|
GovernorSettings.cpp GovernorSettings.hpp
|
||||||
SysExec.cpp SysExec.hpp
|
SysExec.cpp SysExec.hpp
|
||||||
BeastServer.cpp BeastServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp
|
BeastServer.cpp BeastServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp
|
||||||
WifiConfigSettings.hpp WifiConfigSettings.cpp
|
WifiConfigSettings.hpp WifiConfigSettings.cpp
|
||||||
@@ -233,6 +236,7 @@ add_executable(pipedalshutdownd ShutdownMain.cpp CommandLineParser.hpp
|
|||||||
SetWifiConfig.hpp SetWifiConfig.cpp
|
SetWifiConfig.hpp SetWifiConfig.cpp
|
||||||
SystemConfigFile.hpp SystemConfigFile.cpp
|
SystemConfigFile.hpp SystemConfigFile.cpp
|
||||||
SysExec.hpp SysExec.cpp
|
SysExec.hpp SysExec.cpp
|
||||||
|
CpuGovernor.cpp CpuGovernor.hpp
|
||||||
asan_options.cpp
|
asan_options.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(pipedalshutdownd PRIVATE pthread atomic stdc++fs systemd)
|
target_link_libraries(pipedalshutdownd PRIVATE pthread atomic stdc++fs systemd)
|
||||||
|
|||||||
+6
-5
@@ -650,7 +650,7 @@ int main(int argc, char **argv)
|
|||||||
<< " (only valid with the -install option). Usually determined " << endl
|
<< " (only valid with the -install option). Usually determined " << endl
|
||||||
<< " automatically." << endl
|
<< " automatically." << endl
|
||||||
<< endl
|
<< endl
|
||||||
<< " --uninstall Remove installed services and service accounts." << endl
|
<< " --uninstall Remove installed services." << endl
|
||||||
<< endl
|
<< endl
|
||||||
<< " --enable Start the pipedal service at boot time." << endl
|
<< " --enable Start the pipedal service at boot time." << endl
|
||||||
<< endl
|
<< endl
|
||||||
@@ -668,10 +668,11 @@ int main(int argc, char **argv)
|
|||||||
<< " web server will listen on 0.0.0.0 (any)." << endl
|
<< " web server will listen on 0.0.0.0 (any)." << endl
|
||||||
<< endl
|
<< endl
|
||||||
<< " --enable_ap <country_code> <ssid> <wep_password> <channel>" << endl
|
<< " --enable_ap <country_code> <ssid> <wep_password> <channel>" << endl
|
||||||
<< " Enable the Wi-Fi access point. <country_code> is the 2-letter " << endl
|
<< " Enable the Wi-Fi access point. <country_code> is the " << endl
|
||||||
<< " ISO-3166 country code for the country in which you are currently" << endl
|
<< " 2-letter ISO-3166 country code for the country in " << endl
|
||||||
<< " located. The country code determines which channels may be legally" << endl
|
<< " which you are currently located. The country code " << endl
|
||||||
<< " used in (and which features need to be enabled) in order to use a " << endl
|
<< " determines which channels may be legally used in (and " << endl
|
||||||
|
<< " which features need to be enabled) in order to use a " << endl
|
||||||
<< " Wi-Fi channel in your legislative regime." << endl
|
<< " Wi-Fi channel in your legislative regime." << endl
|
||||||
<< endl
|
<< endl
|
||||||
<< " --disable_ap Disabled the Wi-Fi access point." << endl
|
<< " --disable_ap Disabled the Wi-Fi access point." << endl
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
// Copyright (c) 2022 Robin 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.
|
||||||
|
|
||||||
|
#include "CpuGovernor.hpp"
|
||||||
|
#include "ss.hpp"
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include "PiPedalException.hpp"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
using namespace pipedal;
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
|
||||||
|
// not a feature on Win32.
|
||||||
|
void pipedal::SetCpuGovernor(const std::string &governor) { }
|
||||||
|
std::vector<std::string> pipedal::GetAvailableGovernors() { return std::vector<std::string>(); }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static const int SYSFS_RETRIES = 3;
|
||||||
|
|
||||||
|
|
||||||
|
std::string pipedal::GetCpuGovernor()
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
try {
|
||||||
|
std::ifstream f("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
|
||||||
|
f >> result;
|
||||||
|
} catch (const std::exception &)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool writeAndVerify(std::filesystem::path&sysfsPath, const std::string &value)
|
||||||
|
{
|
||||||
|
// return if the value has already been set.
|
||||||
|
{
|
||||||
|
std::ifstream f;
|
||||||
|
f.open(sysfsPath);
|
||||||
|
if (f.is_open())
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
std::getline(f,line);
|
||||||
|
if (!f.fail() && value == line)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < SYSFS_RETRIES; ++i)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// write the value.
|
||||||
|
// write the value.
|
||||||
|
std::ofstream f;
|
||||||
|
f.open(sysfsPath);
|
||||||
|
if (f.is_open())
|
||||||
|
{
|
||||||
|
f << value;
|
||||||
|
} else {
|
||||||
|
std::cout << SS("Can't open " << sysfsPath << " for writing.") << std::endl;
|
||||||
|
sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// verify that we wrote it
|
||||||
|
{
|
||||||
|
std::ifstream f;
|
||||||
|
f.open(sysfsPath);
|
||||||
|
if (f.is_open())
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
std::getline(f,line);
|
||||||
|
if (value == line)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::cout << "Read value: " << line << "Expected value: " << value << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << "Failed to update " << sysfsPath << std::endl;
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pipedal::SetCpuGovernor(const std::string &governor) {
|
||||||
|
// using sysfs
|
||||||
|
int nCpu = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
std::filesystem::path base = SS("/sys/devices/system/cpu/cpu" << nCpu);
|
||||||
|
if (!std::filesystem::is_directory(base))
|
||||||
|
break;
|
||||||
|
|
||||||
|
std::filesystem::path sysFsPath = SS("/sys/devices/system/cpu/cpu" << nCpu << "/cpufreq/scaling_governor");
|
||||||
|
|
||||||
|
if (!writeAndVerify(sysFsPath,governor))
|
||||||
|
{
|
||||||
|
throw PiPedalException(SS("Write to " << sysFsPath << " failed."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++nCpu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<std::string> pipedal::GetAvailableGovernors() {
|
||||||
|
return std::vector<std::string> {
|
||||||
|
"performance",
|
||||||
|
"ondemand",
|
||||||
|
"powersave"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void SetCpuGovernor(const std::string &governor);
|
||||||
|
|
||||||
|
std::vector<std::string> GetAvailableGovernors();
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (c) 2022 Robin 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.
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace pipedal {
|
||||||
|
std::string GetCpuGovernor();
|
||||||
|
|
||||||
|
void SetCpuGovernor(const std::string &governor);
|
||||||
|
|
||||||
|
std::vector<std::string> GetAvailableGovernors();
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2022 Robin 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.
|
||||||
|
|
||||||
|
#include "GovernorSettings.hpp"
|
||||||
|
|
||||||
|
using namespace pipedal;
|
||||||
|
|
||||||
|
JSON_MAP_BEGIN(GovernorSettings)
|
||||||
|
JSON_MAP_REFERENCE(GovernorSettings, governor)
|
||||||
|
JSON_MAP_REFERENCE(GovernorSettings, governors)
|
||||||
|
JSON_MAP_END()
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) 2022 Robin 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "json.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace pipedal {
|
||||||
|
|
||||||
|
class GovernorSettings {
|
||||||
|
public:
|
||||||
|
std::string governor_;
|
||||||
|
std::vector<std::string> governors_;
|
||||||
|
|
||||||
|
DECLARE_JSON_MAP(GovernorSettings);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,360 @@
|
|||||||
|
// Copyright (c) 2022 Robin 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.
|
||||||
|
|
||||||
|
#include "Ipv6Helpers.hpp"
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include "ss.hpp"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <exception>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
using namespace pipedal;
|
||||||
|
|
||||||
|
std::string pipedal::GetLinkLocalAddress(const std::string fromAddress);
|
||||||
|
|
||||||
|
static bool IsIpv4MappedAddress(const struct in6_addr &inetAddr6)
|
||||||
|
{
|
||||||
|
return IN6_IS_ADDR_V4MAPPED(&inetAddr6) != 0;
|
||||||
|
}
|
||||||
|
static uint32_t GetIpv4MappedAddress(const struct in6_addr &inetAddr6)
|
||||||
|
{
|
||||||
|
if (!IsIpv4MappedAddress(inetAddr6))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint8_t *p = (uint8_t *)&inetAddr6;
|
||||||
|
return htonl(*(uint32_t *)(p + 12));
|
||||||
|
}
|
||||||
|
static bool ipv6NetmaskCompare(const struct in6_addr &left, const struct in6_addr &right, const struct in6_addr &mask)
|
||||||
|
{
|
||||||
|
uint8_t *pLeft = (uint8_t *)&left;
|
||||||
|
uint8_t *pRight = (uint8_t *)&right;
|
||||||
|
uint8_t *pMask = (uint8_t *)&mask;
|
||||||
|
for (int i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
if ((pLeft[i] & pMask[i]) != (pRight[i] & pMask[i]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsIpv4OnLocalSubnet(uint32_t ipv4Addres)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
struct ifaddrs *ifap = nullptr;
|
||||||
|
if (getifaddrs(&ifap) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||||
|
{
|
||||||
|
if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||||
|
{ // TODO: Add support for AF_INET6
|
||||||
|
uint32_t netmask = htonl(((sockaddr_in *)(p->ifa_netmask))->sin_addr.s_addr);
|
||||||
|
uint32_t ifAddr = htonl(((sockaddr_in *)(p->ifa_addr))->sin_addr.s_addr);
|
||||||
|
|
||||||
|
if ((netmask & ifAddr) == (netmask & ipv4Addres))
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string StripPortNumber(const std::string &fromAddress)
|
||||||
|
{
|
||||||
|
std::string address = fromAddress;
|
||||||
|
|
||||||
|
if (address.size() == 0)
|
||||||
|
return fromAddress;
|
||||||
|
|
||||||
|
char lastChar = address[address.size() - 1];
|
||||||
|
size_t pos = address.find_last_of(':');
|
||||||
|
|
||||||
|
// if ipv6, make sure we found an actual port address.
|
||||||
|
size_t posBracket = address.find_last_of(']');
|
||||||
|
if (posBracket != std::string::npos && pos != std::string::npos)
|
||||||
|
{
|
||||||
|
if (posBracket > pos)
|
||||||
|
{
|
||||||
|
pos = std::string::npos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
address = address.substr(0, pos);
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pipedal::IsOnLocalSubnet(const std::string &fromAddress)
|
||||||
|
{
|
||||||
|
std::string address = StripPortNumber(fromAddress);
|
||||||
|
if (address.length() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
if (address[0] != '[')
|
||||||
|
{
|
||||||
|
// ipv4
|
||||||
|
struct in_addr inetAddr;
|
||||||
|
memset(&inetAddr, 0, sizeof(inetAddr));
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET, address.c_str(), &inetAddr) == 1)
|
||||||
|
{
|
||||||
|
uint32_t remoteAddress = htonl(inetAddr.s_addr);
|
||||||
|
|
||||||
|
result = IsIpv4OnLocalSubnet(remoteAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ipv6
|
||||||
|
if (address[0] != '[' || address[address.length() - 1] != ']')
|
||||||
|
return false;
|
||||||
|
address = address.substr(1, address.length() - 2);
|
||||||
|
// strip scope if neccessary.
|
||||||
|
auto pos = address.find_last_of('%');
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
address = address.substr(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct in6_addr inetAddr6;
|
||||||
|
memset(&inetAddr6, 0, sizeof(inetAddr6));
|
||||||
|
if (inet_pton(AF_INET6, address.c_str(), &inetAddr6) == 1)
|
||||||
|
{
|
||||||
|
int32_t remoteAddress = -1;
|
||||||
|
// cases:
|
||||||
|
// [::FFFF:ipv4 address]
|
||||||
|
// [FE80:: ] link local.
|
||||||
|
// [FEC0:: ] site local.
|
||||||
|
// others?
|
||||||
|
if (IsIpv4MappedAddress(inetAddr6))
|
||||||
|
{
|
||||||
|
uint32_t remoteAddress = GetIpv4MappedAddress(inetAddr6);
|
||||||
|
return IsIpv4OnLocalSubnet(remoteAddress);
|
||||||
|
}
|
||||||
|
if (IN6_IS_ADDR_LINKLOCAL(&inetAddr6))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (IN6_IS_ADDR_SITELOCAL(&inetAddr6))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#if JUNK
|
||||||
|
// if the address is global, we have to reject it.
|
||||||
|
// no point in going further.
|
||||||
|
struct ifaddrs *ifap = nullptr;
|
||||||
|
if (getifaddrs(&ifap) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int SITE_LOCAL_SCOPE = 5;
|
||||||
|
|
||||||
|
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||||
|
{
|
||||||
|
if (p->ifa_addr->sa_family == AF_INET6 && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)(p->ifa_addr);
|
||||||
|
struct sockaddr_in6 *pNetMask = (struct sockaddr_in6 *)(p->ifa_netmask);
|
||||||
|
if (pAddr->sin6_scope_id <= SITE_LOCAL_SCOPE)
|
||||||
|
{
|
||||||
|
if (ipv6NetmaskCompare(inetAddr6, pAddr->sin6_addr, pNetMask->sin6_addr))
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetInterfaceForIp4Address(uint32_t ipv4Address)
|
||||||
|
{
|
||||||
|
struct ifaddrs *ifap = nullptr;
|
||||||
|
if (getifaddrs(&ifap) != 0)
|
||||||
|
return "";
|
||||||
|
std::string result;
|
||||||
|
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||||
|
{
|
||||||
|
if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||||
|
{ // TODO: Add support for AF_INET6
|
||||||
|
uint32_t netmask = htonl(((sockaddr_in *)(p->ifa_netmask))->sin_addr.s_addr);
|
||||||
|
uint32_t ifAddr = htonl(((sockaddr_in *)(p->ifa_addr))->sin_addr.s_addr);
|
||||||
|
|
||||||
|
if ((netmask & ifAddr) == (netmask & ipv4Address))
|
||||||
|
{
|
||||||
|
result = p->ifa_name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetInterfaceForIp6Address(const in6_addr inetAddr6)
|
||||||
|
{
|
||||||
|
struct ifaddrs *ifap = nullptr;
|
||||||
|
if (getifaddrs(&ifap) != 0)
|
||||||
|
return "";
|
||||||
|
std::string result;
|
||||||
|
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||||
|
{
|
||||||
|
if (p->ifa_addr->sa_family == AF_INET6 && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||||
|
{ // TODO: Add support for AF_INET6
|
||||||
|
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)(p->ifa_addr);
|
||||||
|
struct sockaddr_in6 *pNetMask = (struct sockaddr_in6 *)(p->ifa_netmask);
|
||||||
|
if (ipv6NetmaskCompare(inetAddr6, pAddr->sin6_addr, pNetMask->sin6_addr))
|
||||||
|
{
|
||||||
|
result = p->ifa_name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetLinkLocalAddressForInterface(const std::string &name)
|
||||||
|
{
|
||||||
|
struct ifaddrs *ifap = nullptr;
|
||||||
|
if (getifaddrs(&ifap) != 0)
|
||||||
|
return "";
|
||||||
|
std::string result;
|
||||||
|
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||||
|
{
|
||||||
|
if (p->ifa_addr->sa_family == AF_INET6 && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||||
|
{ // TODO: Add support for AF_INET6
|
||||||
|
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)(p->ifa_addr);
|
||||||
|
if (IN6_IS_ADDR_LINKLOCAL(&(pAddr->sin6_addr)))
|
||||||
|
{
|
||||||
|
if (name.length() == 0 || name == p->ifa_name)
|
||||||
|
{
|
||||||
|
const int BUFSIZE = 128;
|
||||||
|
char host[BUFSIZE];
|
||||||
|
if (getnameinfo(p->ifa_addr, sizeof(struct sockaddr_in6), host, BUFSIZE, NULL, 0, NI_NUMERICHOST) == 0)
|
||||||
|
{
|
||||||
|
host[BUFSIZE - 1] = '\0';
|
||||||
|
|
||||||
|
// trim the interface spec if present
|
||||||
|
for (char *p = host; *p != 0; ++p)
|
||||||
|
{
|
||||||
|
if (*p == '%')
|
||||||
|
{
|
||||||
|
*p = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = SS('[' << host << ']');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string pipedal::GetLinkLocalAddress(const std::string fromAddress)
|
||||||
|
{
|
||||||
|
std::string address = StripPortNumber(fromAddress);
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
if (address[0] != '[')
|
||||||
|
{
|
||||||
|
// ipv4
|
||||||
|
struct in_addr inetAddr;
|
||||||
|
memset(&inetAddr, 0, sizeof(inetAddr));
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET, address.c_str(), &inetAddr) == 1)
|
||||||
|
{
|
||||||
|
uint32_t remoteAddress = htonl(inetAddr.s_addr);
|
||||||
|
std::string interfaceName = GetInterfaceForIp4Address(remoteAddress);
|
||||||
|
result = GetLinkLocalAddressForInterface(interfaceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ipv6
|
||||||
|
if (address[0] != '[' || address[address.length() - 1] != ']')
|
||||||
|
throw std::invalid_argument("Bad address.");
|
||||||
|
address = address.substr(1, address.length() - 2);
|
||||||
|
// strip scope if neccessary.
|
||||||
|
auto pos = address.find_last_of('%');
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
address = address.substr(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct in6_addr inetAddr6;
|
||||||
|
memset(&inetAddr6, 0, sizeof(inetAddr6));
|
||||||
|
if (inet_pton(AF_INET6, address.c_str(), &inetAddr6) == 1)
|
||||||
|
{
|
||||||
|
int32_t remoteAddress = -1;
|
||||||
|
// cases:
|
||||||
|
// [::FFFF:ipv4 address]
|
||||||
|
// [FE80:: ] link local.
|
||||||
|
// [FEC0:: ] site local.
|
||||||
|
// others?
|
||||||
|
if (IN6_IS_ADDR_LINKLOCAL(&inetAddr6))
|
||||||
|
{
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
if (IN6_IS_ADDR_SITELOCAL(&inetAddr6))
|
||||||
|
{
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string interfaceName;
|
||||||
|
if (IsIpv4MappedAddress(inetAddr6))
|
||||||
|
{
|
||||||
|
uint32_t remoteAddress = GetIpv4MappedAddress(inetAddr6);
|
||||||
|
interfaceName = GetInterfaceForIp4Address(remoteAddress);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
interfaceName = GetInterfaceForIp6Address(inetAddr6);
|
||||||
|
}
|
||||||
|
result = GetLinkLocalAddressForInterface(interfaceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result == "")
|
||||||
|
{
|
||||||
|
result = GetLinkLocalAddressForInterface("");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (c) 2022 Robin 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
namespace pipedal {
|
||||||
|
|
||||||
|
|
||||||
|
std::string GetLinkLocalAddress(const std::string fromAddress);
|
||||||
|
|
||||||
|
bool IsOnLocalSubnet(const std::string&fromAddress);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+2
-9
@@ -33,6 +33,7 @@ using namespace pipedal;
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include "VuUpdate.hpp"
|
#include "VuUpdate.hpp"
|
||||||
|
#include "CpuGovernor.hpp"
|
||||||
|
|
||||||
#include "RingBuffer.hpp"
|
#include "RingBuffer.hpp"
|
||||||
#include "RingBufferReader.hpp"
|
#include "RingBufferReader.hpp"
|
||||||
@@ -99,15 +100,7 @@ static void GetCpuFrequency(uint64_t*freqMin,uint64_t*freqMax)
|
|||||||
}
|
}
|
||||||
static std::string GetGovernor()
|
static std::string GetGovernor()
|
||||||
{
|
{
|
||||||
std::string result;
|
return pipedal::GetCpuGovernor();
|
||||||
try {
|
|
||||||
std::ifstream f("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
|
|
||||||
f >> result;
|
|
||||||
} catch (const std::exception &)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+52
-1
@@ -26,6 +26,7 @@
|
|||||||
#include "PiPedalConfiguration.hpp"
|
#include "PiPedalConfiguration.hpp"
|
||||||
#include "ShutdownClient.hpp"
|
#include "ShutdownClient.hpp"
|
||||||
#include "SplitEffect.hpp"
|
#include "SplitEffect.hpp"
|
||||||
|
#include "CpuGovernor.hpp"
|
||||||
|
|
||||||
#ifndef NO_MLOCK
|
#ifndef NO_MLOCK
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@@ -76,15 +77,32 @@ void PiPedalModel::Close()
|
|||||||
|
|
||||||
PiPedalModel::~PiPedalModel()
|
PiPedalModel::~PiPedalModel()
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
|
ShutdownClient::UnmonitorGovernor();
|
||||||
|
} catch (...) // noexcept here!
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
CurrentPreset currentPreset;
|
CurrentPreset currentPreset;
|
||||||
currentPreset.modified_ = this->hasPresetChanged;
|
currentPreset.modified_ = this->hasPresetChanged;
|
||||||
currentPreset.preset_ = this->pedalBoard;
|
currentPreset.preset_ = this->pedalBoard;
|
||||||
storage.SaveCurrentPreset(currentPreset);
|
storage.SaveCurrentPreset(currentPreset);
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
if (jackHost)
|
if (jackHost)
|
||||||
{
|
{
|
||||||
jackHost->Close();
|
jackHost->Close();
|
||||||
}
|
}
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -134,7 +152,7 @@ void PiPedalModel::Load(const PiPedalConfiguration &configuration)
|
|||||||
this->webRoot = configuration.GetWebRoot();
|
this->webRoot = configuration.GetWebRoot();
|
||||||
this->jackServerSettings.ReadJackConfiguration();
|
this->jackServerSettings.ReadJackConfiguration();
|
||||||
|
|
||||||
|
ShutdownClient::MonitorGovernor(storage.GetGovernorSettings());
|
||||||
|
|
||||||
// lv2Host.Load(configuration.GetLv2Path().c_str());
|
// lv2Host.Load(configuration.GetLv2Path().c_str());
|
||||||
|
|
||||||
@@ -594,6 +612,39 @@ bool PiPedalModel::RenamePreset(int64_t clientId, int64_t instanceId, const std:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GovernorSettings PiPedalModel::GetGovernorSettings()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
|
GovernorSettings result;
|
||||||
|
result.governor_ = storage.GetGovernorSettings();
|
||||||
|
result.governors_ = pipedal::GetAvailableGovernors();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void PiPedalModel::SetGovernorSettings(const std::string& governor)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
|
ShutdownClient::SetGovernorSettings(governor);
|
||||||
|
|
||||||
|
this->storage.SetGovernorSettings(governor);
|
||||||
|
|
||||||
|
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();
|
||||||
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
t[i]->OnGovernorSettingsChanged(governor);
|
||||||
|
}
|
||||||
|
delete[] t;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
|
void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "Lv2Host.hpp"
|
#include "Lv2Host.hpp"
|
||||||
|
#include "GovernorSettings.hpp"
|
||||||
#include "PedalBoard.hpp"
|
#include "PedalBoard.hpp"
|
||||||
#include "Storage.hpp"
|
#include "Storage.hpp"
|
||||||
#include "Banks.hpp"
|
#include "Banks.hpp"
|
||||||
@@ -57,6 +58,7 @@ public:
|
|||||||
virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) = 0;
|
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 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 OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) = 0;
|
||||||
|
virtual void OnGovernorSettingsChanged(const std::string &governor) = 0;
|
||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -194,6 +196,9 @@ public:
|
|||||||
void SetWifiConfigSettings(const WifiConfigSettings&wifiConfigSettings);
|
void SetWifiConfigSettings(const WifiConfigSettings&wifiConfigSettings);
|
||||||
WifiConfigSettings GetWifiConfigSettings();
|
WifiConfigSettings GetWifiConfigSettings();
|
||||||
|
|
||||||
|
void SetGovernorSettings(const std::string& governor);
|
||||||
|
GovernorSettings GetGovernorSettings();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int64_t AddVuSubscription(int64_t instanceId);
|
int64_t AddVuSubscription(int64_t instanceId);
|
||||||
|
|||||||
+20
-1
@@ -28,6 +28,7 @@
|
|||||||
#include "JackConfiguration.hpp"
|
#include "JackConfiguration.hpp"
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include "Ipv6Helpers.hpp"
|
||||||
|
|
||||||
#include "ShutdownClient.hpp"
|
#include "ShutdownClient.hpp"
|
||||||
#include "WifiConfigSettings.hpp"
|
#include "WifiConfigSettings.hpp"
|
||||||
@@ -804,6 +805,17 @@ public:
|
|||||||
this->Reply(replyTo,"setJackserverSettings");
|
this->Reply(replyTo,"setJackserverSettings");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if (message == "setGovernorSettings") {
|
||||||
|
std::string governor;
|
||||||
|
pReader->read(&governor);
|
||||||
|
std::string fromAddress = this->getFromAddress();
|
||||||
|
if (!IsOnLocalSubnet(fromAddress))
|
||||||
|
{
|
||||||
|
throw PiPedalException("Permission denied. Not on local subnet.");
|
||||||
|
}
|
||||||
|
this->model.SetGovernorSettings(governor);
|
||||||
|
this->Reply(replyTo,"setGovernorSettings");
|
||||||
|
}
|
||||||
else if (message == "setWifiConfigSettings") {
|
else if (message == "setWifiConfigSettings") {
|
||||||
WifiConfigSettings wifiConfigSettings;
|
WifiConfigSettings wifiConfigSettings;
|
||||||
pReader->read(&wifiConfigSettings);
|
pReader->read(&wifiConfigSettings);
|
||||||
@@ -812,7 +824,7 @@ public:
|
|||||||
throw PiPedalException("Can't change server settings when running interactively.");
|
throw PiPedalException("Can't change server settings when running interactively.");
|
||||||
}
|
}
|
||||||
std::string fromAddress = this->getFromAddress();
|
std::string fromAddress = this->getFromAddress();
|
||||||
if (!ShutdownClient::IsOnLocalSubnet(fromAddress))
|
if (!IsOnLocalSubnet(fromAddress))
|
||||||
{
|
{
|
||||||
throw PiPedalException("Permission denied. Not on local subnet.");
|
throw PiPedalException("Permission denied. Not on local subnet.");
|
||||||
}
|
}
|
||||||
@@ -824,6 +836,10 @@ public:
|
|||||||
else if (message == "getWifiConfigSettings") {
|
else if (message == "getWifiConfigSettings") {
|
||||||
this->Reply(replyTo, "getWifiConfigSettings", model.GetWifiConfigSettings());
|
this->Reply(replyTo, "getWifiConfigSettings", model.GetWifiConfigSettings());
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (message == "getGovernorSettings") {
|
||||||
|
this->Reply(replyTo, "getGovernorSettings", model.GetGovernorSettings());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (message == "getJackServerSettings") {
|
else if (message == "getJackServerSettings") {
|
||||||
@@ -1461,6 +1477,9 @@ public:
|
|||||||
virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) {
|
virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) {
|
||||||
Send("onWifiConfigSettingsChanged",wifiConfigSettings);
|
Send("onWifiConfigSettingsChanged",wifiConfigSettings);
|
||||||
}
|
}
|
||||||
|
virtual void OnGovernorSettingsChanged(const std::string& governor) {
|
||||||
|
Send("onGovernorSettingsChanged",governor);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard)
|
virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard)
|
||||||
{
|
{
|
||||||
|
|||||||
+52
-46
@@ -27,6 +27,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
|
#include "Ipv6Helpers.hpp"
|
||||||
|
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
@@ -165,57 +166,12 @@ bool ShutdownClient::SetJackServerConfiguration(const JackServerSettings & jackS
|
|||||||
return WriteMessage(s.str().c_str());
|
return WriteMessage(s.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShutdownClient::IsOnLocalSubnet(const std::string&fromAddress)
|
|
||||||
{
|
|
||||||
std::string address = fromAddress;
|
|
||||||
if (address.size() == 0) return false;
|
|
||||||
char lastChar = address[address.size()-1];
|
|
||||||
if (address[0] != '[' || lastChar != ']') // i.e. not an ipv6 address;
|
|
||||||
{
|
|
||||||
size_t pos = address.find_last_of(':');
|
|
||||||
if (pos != std::string::npos)
|
|
||||||
{
|
|
||||||
address = address.substr(0,pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (address[0] == '[') return false;
|
|
||||||
|
|
||||||
char buf[512];
|
|
||||||
|
|
||||||
struct in_addr inetAddr;
|
|
||||||
|
|
||||||
memset(&inetAddr,0,sizeof(inetAddr));
|
|
||||||
|
|
||||||
if (inet_pton(AF_INET,address.c_str(),&inetAddr) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint32_t remoteAddress = htonl(inetAddr.s_addr);
|
|
||||||
|
|
||||||
struct ifaddrs *ifap = nullptr;
|
|
||||||
if (getifaddrs(&ifap) != 0) return false;
|
|
||||||
|
|
||||||
bool result = false;
|
|
||||||
for (ifaddrs*p = ifap; p != nullptr; p = p->ifa_next) {
|
|
||||||
if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr) { // TODO: Add support for AF_INET6
|
|
||||||
uint32_t netmask = htonl(((sockaddr_in*)(p->ifa_netmask))->sin_addr.s_addr);
|
|
||||||
uint32_t ifAddr = htonl(((sockaddr_in*)(p->ifa_addr))->sin_addr.s_addr);
|
|
||||||
|
|
||||||
if ((netmask & ifAddr) == (netmask & remoteAddress))
|
|
||||||
{
|
|
||||||
result = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
freeifaddrs(ifap);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShutdownClient::SetWifiConfig(const WifiConfigSettings & settings)
|
void ShutdownClient::SetWifiConfig(const WifiConfigSettings & settings)
|
||||||
{
|
{
|
||||||
if (!CanUseShutdownClient())
|
if (!CanUseShutdownClient())
|
||||||
{
|
{
|
||||||
throw PiPedalException("Can't use ShutdownClient when running interactively.");
|
throw PiPedalException("Can't perform this operation when debugging.");
|
||||||
}
|
}
|
||||||
std::stringstream cmd;
|
std::stringstream cmd;
|
||||||
cmd << "WifiConfigSettings ";
|
cmd << "WifiConfigSettings ";
|
||||||
@@ -227,3 +183,53 @@ void ShutdownClient::SetWifiConfig(const WifiConfigSettings & settings)
|
|||||||
throw PiPedalException("Operation failed.");
|
throw PiPedalException("Operation failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShutdownClient::SetGovernorSettings(const std::string & settings)
|
||||||
|
{
|
||||||
|
if (!CanUseShutdownClient())
|
||||||
|
{
|
||||||
|
throw PiPedalException("Can't use ShutdownClient when running interactively.");
|
||||||
|
}
|
||||||
|
std::stringstream cmd;
|
||||||
|
cmd << "GovernorSettings ";
|
||||||
|
json_writer writer(cmd,true);
|
||||||
|
writer.write(settings);
|
||||||
|
cmd << '\n';
|
||||||
|
bool result = WriteMessage(cmd.str().c_str());
|
||||||
|
if (!result) { // unexpected. Should throw exception on failure.
|
||||||
|
throw PiPedalException("Operation failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShutdownClient::MonitorGovernor(const std::string &governor)
|
||||||
|
{
|
||||||
|
if (!CanUseShutdownClient())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::stringstream cmd;
|
||||||
|
cmd << "MonitorGovernor ";
|
||||||
|
json_writer writer(cmd,true);
|
||||||
|
writer.write(governor);
|
||||||
|
cmd << '\n';
|
||||||
|
bool result = WriteMessage(cmd.str().c_str());
|
||||||
|
if (!result) { // unexpected. Should throw exception on failure.
|
||||||
|
throw PiPedalException("Operation failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
void ShutdownClient::UnmonitorGovernor()
|
||||||
|
{
|
||||||
|
if (!CanUseShutdownClient())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::stringstream cmd;
|
||||||
|
cmd << "UnmonitorGovernor";
|
||||||
|
cmd << '\n';
|
||||||
|
bool result = WriteMessage(cmd.str().c_str());
|
||||||
|
if (!result) { // unexpected. Should throw exception on failure.
|
||||||
|
throw PiPedalException("Operation failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,14 +25,17 @@
|
|||||||
|
|
||||||
namespace pipedal {
|
namespace pipedal {
|
||||||
|
|
||||||
|
|
||||||
class ShutdownClient {
|
class ShutdownClient {
|
||||||
static bool WriteMessage(const char*message);
|
static bool WriteMessage(const char*message);
|
||||||
public:
|
public:
|
||||||
static bool CanUseShutdownClient();
|
static bool CanUseShutdownClient();
|
||||||
static bool RequestShutdown(bool restart);
|
static bool RequestShutdown(bool restart);
|
||||||
static bool SetJackServerConfiguration(const JackServerSettings & jackServerSettings);
|
static bool SetJackServerConfiguration(const JackServerSettings & jackServerSettings);
|
||||||
static bool IsOnLocalSubnet(const std::string&fromAddress);
|
|
||||||
static void SetWifiConfig(const WifiConfigSettings & settings);
|
static void SetWifiConfig(const WifiConfigSettings & settings);
|
||||||
|
static void SetGovernorSettings(const std::string & governor);
|
||||||
|
static void MonitorGovernor(const std::string &governor);
|
||||||
|
static void UnmonitorGovernor();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
+206
-97
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "CommandLineParser.hpp"
|
#include "CommandLineParser.hpp"
|
||||||
|
#include "CpuGovernor.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
@@ -40,7 +41,10 @@
|
|||||||
#include "SetWifiConfig.hpp"
|
#include "SetWifiConfig.hpp"
|
||||||
#include "SysExec.hpp"
|
#include "SysExec.hpp"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
@@ -50,15 +54,122 @@ using ip::tcp;
|
|||||||
|
|
||||||
const size_t MAX_LENGTH = 128;
|
const size_t MAX_LENGTH = 128;
|
||||||
|
|
||||||
|
class GovernorMonitorThread
|
||||||
|
|
||||||
static bool startsWith(const std::string&s, const char*text)
|
|
||||||
{
|
{
|
||||||
if (s.length() < strlen(text)) return false;
|
public:
|
||||||
const char*sp = s.c_str();
|
~GovernorMonitorThread()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
void Start(std::string governor)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
if (!pThread)
|
||||||
|
{
|
||||||
|
this->governor = governor;
|
||||||
|
cancelled = false;
|
||||||
|
wake = false;
|
||||||
|
pThread = std::make_unique<std::thread>([this]()
|
||||||
|
{ this->ServiceProc(); });
|
||||||
|
} else {
|
||||||
|
this->governor = governor;
|
||||||
|
wake = true;
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
cv.notify_one();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Stop()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
if (pThread)
|
||||||
|
{
|
||||||
|
wake = true;
|
||||||
|
cancelled = true;
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
cv.notify_one();
|
||||||
|
pThread->join();
|
||||||
|
pThread.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SetGovernor(const std::string &governor)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
wake = true;
|
||||||
|
this->governor = governor;
|
||||||
|
}
|
||||||
|
cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool wake = false;
|
||||||
|
bool cancelled = false;
|
||||||
|
std::string savedGovernor;
|
||||||
|
void ServiceProc()
|
||||||
|
{
|
||||||
|
savedGovernor = pipedal::GetCpuGovernor();
|
||||||
|
pipedal::SetCpuGovernor(this->governor);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bool cancelled;
|
||||||
|
std::string governor;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
auto timeToWaitFor = std::chrono::system_clock::now() + 5000ms;
|
||||||
|
cv.wait_until(
|
||||||
|
lock,
|
||||||
|
timeToWaitFor,
|
||||||
|
[this]()
|
||||||
|
{ return wake; });
|
||||||
|
wake = false;
|
||||||
|
governor = this->governor;
|
||||||
|
cancelled = this->cancelled;
|
||||||
|
}
|
||||||
|
if (cancelled) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::string activeGovernor = pipedal::GetCpuGovernor();
|
||||||
|
if (activeGovernor != governor)
|
||||||
|
{
|
||||||
|
// somebody set it so they must have wanted it.
|
||||||
|
// save the value so that we can restore it when done.
|
||||||
|
savedGovernor = activeGovernor;
|
||||||
|
|
||||||
|
// but insist on using ours!!
|
||||||
|
pipedal::SetCpuGovernor(governor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pipedal::SetCpuGovernor(savedGovernor);
|
||||||
|
}
|
||||||
|
std::unique_ptr<std::thread> pThread;
|
||||||
|
std::string governor;
|
||||||
|
std::mutex mutex;
|
||||||
|
bool canceled;
|
||||||
|
std::condition_variable cv;
|
||||||
|
};
|
||||||
|
|
||||||
|
GovernorMonitorThread governorMonitorThread;
|
||||||
|
|
||||||
|
void StopGovernorMonitorThread()
|
||||||
|
{
|
||||||
|
governorMonitorThread.Stop();
|
||||||
|
}
|
||||||
|
void StartGovernorMonitorThread(const std::string&governor)
|
||||||
|
{
|
||||||
|
governorMonitorThread.Start(governor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool startsWith(const std::string &s, const char *text)
|
||||||
|
{
|
||||||
|
if (s.length() < strlen(text))
|
||||||
|
return false;
|
||||||
|
const char *sp = s.c_str();
|
||||||
while (*text)
|
while (*text)
|
||||||
{
|
{
|
||||||
if (*text++ != *sp++) return false;
|
if (*text++ != *sp++)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -67,7 +178,7 @@ static std::vector<std::string> tokenize(std::string value)
|
|||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
std::stringstream s(value);
|
std::stringstream s(value);
|
||||||
std::string item;
|
std::string item;
|
||||||
while (std::getline(s,item,' '))
|
while (std::getline(s, item, ' '))
|
||||||
{
|
{
|
||||||
if (item.length() != 0)
|
if (item.length() != 0)
|
||||||
result.push_back(item);
|
result.push_back(item);
|
||||||
@@ -75,15 +186,7 @@ static std::vector<std::string> tokenize(std::string value)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CaptureAccessPoint(const std::string gatewayAddress)
|
static void delayedRestartProc()
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
static void ReleaseAccessPoint(const std::string gatewayAddress)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void delayedRestartProc()
|
|
||||||
{
|
{
|
||||||
sleep(1); // give a chance for websocket messages to propagate.
|
sleep(1); // give a chance for websocket messages to propagate.
|
||||||
Lv2Log::error("Delayed Restart");
|
Lv2Log::error("Delayed Restart");
|
||||||
@@ -91,10 +194,9 @@ void delayedRestartProc()
|
|||||||
|
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService";
|
s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService";
|
||||||
if (::system(s.str().c_str())!= EXIT_SUCCESS)
|
if (::system(s.str().c_str()) != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
Lv2Log::error("Delayed Restart failed.");
|
Lv2Log::error("Delayed Restart failed.");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,8 +212,6 @@ bool setJackConfiguration(JackServerSettings serverSettings)
|
|||||||
std::thread delayedRestartThread(delayedRestartProc);
|
std::thread delayedRestartThread(delayedRestartProc);
|
||||||
delayedRestartThread.detach();
|
delayedRestartThread.detach();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Reader : public std::enable_shared_from_this<Reader>
|
class Reader : public std::enable_shared_from_this<Reader>
|
||||||
@@ -162,7 +262,7 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
socket.async_write_some(
|
socket.async_write_some(
|
||||||
boost::asio::buffer(response.c_str()+ writePosition, response.length()-writePosition),
|
boost::asio::buffer(response.c_str() + writePosition, response.length() - writePosition),
|
||||||
boost::bind(&Reader::HandleWrite,
|
boost::bind(&Reader::HandleWrite,
|
||||||
shared_from_this(),
|
shared_from_this(),
|
||||||
boost::asio::placeholders::error,
|
boost::asio::placeholders::error,
|
||||||
@@ -185,7 +285,7 @@ private:
|
|||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
{
|
{
|
||||||
std::string command = message.str();
|
std::string command = message.str();
|
||||||
cout << "Received command: " << command << endl;
|
cout << command << endl;
|
||||||
HandleCommand(command);
|
HandleCommand(command);
|
||||||
socket.close();
|
socket.close();
|
||||||
return;
|
return;
|
||||||
@@ -202,59 +302,88 @@ private:
|
|||||||
socket.close();
|
socket.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void HandleCommand(const std::string &s)
|
void HandleCommand(const std::string &text)
|
||||||
{
|
{
|
||||||
int result = -1;
|
int result = -1;
|
||||||
try {
|
std::string command;
|
||||||
if (startsWith(s,"WifiConfigSettings "))
|
std::string args;
|
||||||
|
auto pos = text.find_first_of(' ');
|
||||||
|
if (pos == std::string::npos)
|
||||||
{
|
{
|
||||||
std::string json = s.substr(strlen("WifiConfigSettings "));
|
command = text;
|
||||||
std::stringstream ss(json);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command = text.substr(0, pos);
|
||||||
|
args = text.substr(pos + 1);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (command == "UnmonitorGovernor")
|
||||||
|
{
|
||||||
|
StopGovernorMonitorThread();
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else if (command == "MonitorGovernor")
|
||||||
|
{
|
||||||
|
std::stringstream ss(args);
|
||||||
|
std::string governor;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json_reader reader(ss);
|
||||||
|
reader.read(&governor);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
throw PiPedalArgumentException("Invalid arguments.");
|
||||||
|
}
|
||||||
|
StartGovernorMonitorThread(governor);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else if (command == "GovernorSettings")
|
||||||
|
{
|
||||||
|
std::stringstream ss(args);
|
||||||
|
std::string governor;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json_reader reader(ss);
|
||||||
|
reader.read(&governor);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
throw PiPedalArgumentException("Invalid arguments.");
|
||||||
|
}
|
||||||
|
governorMonitorThread.SetGovernor(governor);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else if (command == "WifiConfigSettings ")
|
||||||
|
{
|
||||||
|
std::stringstream ss(args);
|
||||||
WifiConfigSettings settings;
|
WifiConfigSettings settings;
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
json_reader reader(ss);
|
json_reader reader(ss);
|
||||||
reader.read(&settings);
|
reader.read(&settings);
|
||||||
} catch (const std::exception &e)
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
throw PiPedalArgumentException("Invalid arguments.");
|
throw PiPedalArgumentException("Invalid arguments.");
|
||||||
}
|
}
|
||||||
pipedal::SetWifiConfig(settings);
|
pipedal::SetWifiConfig(settings);
|
||||||
result = 0;
|
result = 0;
|
||||||
|
|
||||||
} else if (startsWith(s,"release_ap "))
|
|
||||||
{
|
|
||||||
std::vector<std::string> argv = tokenize(s);
|
|
||||||
if (argv.size() == 2) {
|
|
||||||
ReleaseAccessPoint(argv[1]);
|
|
||||||
result = 0;
|
|
||||||
} else {
|
|
||||||
throw PiPedalArgumentException("Invalid arguments.");
|
|
||||||
}
|
}
|
||||||
|
else if (command == "shutdown")
|
||||||
} else if (startsWith(s,"capture_ap "))
|
|
||||||
{
|
|
||||||
std::vector<std::string> argv = tokenize(s);
|
|
||||||
if (argv.size() == 2) {
|
|
||||||
CaptureAccessPoint(argv[1]);
|
|
||||||
result = 0;
|
|
||||||
} else {
|
|
||||||
throw PiPedalArgumentException("Invalid arguments.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} else if (s == "shutdown")
|
|
||||||
{
|
{
|
||||||
result = sysExec("/usr/sbin/shutdown -P now");
|
result = sysExec("/usr/sbin/shutdown -P now");
|
||||||
}
|
}
|
||||||
else if (s == "restart")
|
else if (command == "restart")
|
||||||
{
|
{
|
||||||
result = sysExec("/usr/sbin/shutdown -r now");
|
result = sysExec("/usr/sbin/shutdown -r now");
|
||||||
} else if (startsWith(s,"setJackConfiguration "))
|
}
|
||||||
|
else if (command == "setJackConfiguration")
|
||||||
{
|
{
|
||||||
auto remainder = s.substr(strlen("setJackConfiguration "));
|
|
||||||
|
|
||||||
|
std::stringstream input(args);
|
||||||
std::stringstream input(remainder);
|
|
||||||
JackServerSettings serverSettings;
|
JackServerSettings serverSettings;
|
||||||
json_reader reader(input);
|
json_reader reader(input);
|
||||||
|
|
||||||
@@ -263,12 +392,18 @@ private:
|
|||||||
if (input.fail())
|
if (input.fail())
|
||||||
{
|
{
|
||||||
result = -1;
|
result = -1;
|
||||||
} else {
|
|
||||||
result = setJackConfiguration(serverSettings) ? 0: -1;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = setJackConfiguration(serverSettings) ? 0 : -1;
|
||||||
}
|
}
|
||||||
} catch (const std::exception &e)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::invalid_argument(SS("Unknown command:" << command));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
std::stringstream t;
|
std::stringstream t;
|
||||||
t << "-2 " << e.what() << "\n";
|
t << "-2 " << e.what() << "\n";
|
||||||
@@ -284,7 +419,6 @@ private:
|
|||||||
this->writePosition = 0;
|
this->writePosition = 0;
|
||||||
WriteSome();
|
WriteSome();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Server
|
class Server
|
||||||
@@ -314,7 +448,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//constructor for accepting connection from client
|
// constructor for accepting connection from client
|
||||||
Server(boost::asio::io_service &io_service, const tcp::endpoint &endpoint)
|
Server(boost::asio::io_service &io_service, const tcp::endpoint &endpoint)
|
||||||
: acceptor_(io_service, endpoint),
|
: acceptor_(io_service, endpoint),
|
||||||
io_service(io_service)
|
io_service(io_service)
|
||||||
@@ -322,8 +456,8 @@ public:
|
|||||||
{
|
{
|
||||||
StartAccept();
|
StartAccept();
|
||||||
}
|
}
|
||||||
~Server() {
|
~Server()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -332,29 +466,26 @@ void runServer(uint16_t port)
|
|||||||
asio::ip::tcp::endpoint endpoint(ip::make_address_v4("127.0.0.1"), port);
|
asio::ip::tcp::endpoint endpoint(ip::make_address_v4("127.0.0.1"), port);
|
||||||
asio::io_service ios;
|
asio::io_service ios;
|
||||||
|
|
||||||
try {
|
try
|
||||||
Server server(ios,endpoint);
|
{
|
||||||
|
Server server(ios, endpoint);
|
||||||
ios.run();
|
ios.run();
|
||||||
cout << "Processing terminated." << endl;
|
cout << "Processing terminated." << endl;
|
||||||
} catch (const std::exception & e)
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
cout << "Error: " << e.what() << endl;
|
cout << "Error: " << e.what() << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
Lv2Log::set_logger(MakeLv2SystemdLogger());
|
Lv2Log::set_logger(MakeLv2SystemdLogger());
|
||||||
CommandLineParser parser;
|
CommandLineParser parser;
|
||||||
|
|
||||||
uint16_t port = 0;
|
uint16_t port = 0;
|
||||||
std::string captureAccessPoint;
|
|
||||||
std::string releaseAccessPoint;
|
|
||||||
|
|
||||||
parser.AddOption("-port", &port);
|
parser.AddOption("-port", &port);
|
||||||
parser.AddOption("-captureAP",&captureAccessPoint);
|
|
||||||
parser.AddOption("-releaseAP",&releaseAccessPoint);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -369,34 +500,12 @@ int main(int argc, char **argv)
|
|||||||
cout << "Error: " << e.what() << endl;
|
cout << "Error: " << e.what() << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (captureAccessPoint.length() != 0)
|
if (port == 0)
|
||||||
{
|
{
|
||||||
try{
|
|
||||||
CaptureAccessPoint(captureAccessPoint);
|
|
||||||
|
|
||||||
} catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Error: " << e.what() << std::endl;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
std::cout << "Access point captured." << std::endl;
|
|
||||||
} else if (releaseAccessPoint.length() != 0)
|
|
||||||
{
|
|
||||||
try{
|
|
||||||
ReleaseAccessPoint(releaseAccessPoint);
|
|
||||||
} catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Error: " << e.what() << std::endl;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
std::cout << "Access point released." << std::endl;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (port == 0) {
|
|
||||||
std::cerr << "Error: port not specified." << std::endl;
|
std::cerr << "Error: port not specified." << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
runServer(port);
|
runServer(port);
|
||||||
}
|
governorMonitorThread.Stop();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ const char *BANK_EXTENSION = ".bank";
|
|||||||
const char *BANKS_FILENAME = "index.banks";
|
const char *BANKS_FILENAME = "index.banks";
|
||||||
|
|
||||||
#define WIFI_CONFIG_SETTINGS_FILENAME "wifiConfigSettings.json";
|
#define WIFI_CONFIG_SETTINGS_FILENAME "wifiConfigSettings.json";
|
||||||
|
#define GOVERNOR_SETTINGS_FILENAME "governorSettings.json";
|
||||||
|
|
||||||
Storage::Storage()
|
Storage::Storage()
|
||||||
{
|
{
|
||||||
@@ -182,6 +183,7 @@ void Storage::Initialize()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
LoadWifiConfigSettings();
|
LoadWifiConfigSettings();
|
||||||
|
LoadGovernorSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -802,6 +804,25 @@ int64_t Storage::UploadBank(BankFile&bankFile,int64_t uploadAfter)
|
|||||||
return lastBank;
|
return lastBank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Storage::SetGovernorSettings(const std::string & governor)
|
||||||
|
{
|
||||||
|
std::filesystem::path path = this->dataRoot / GOVERNOR_SETTINGS_FILENAME;
|
||||||
|
{
|
||||||
|
std::ofstream f(path);
|
||||||
|
if (!f.is_open())
|
||||||
|
{
|
||||||
|
throw PiPedalException("Unable to write to " + ((std::string)path));
|
||||||
|
}
|
||||||
|
json_writer writer(f);
|
||||||
|
writer.write(governor);
|
||||||
|
this->governorSettings = governor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string Storage::GetGovernorSettings() const
|
||||||
|
{
|
||||||
|
return this->governorSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Storage::SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings)
|
void Storage::SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings)
|
||||||
{
|
{
|
||||||
@@ -839,7 +860,30 @@ void Storage::SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSetting
|
|||||||
}
|
}
|
||||||
this->wifiConfigSettings = copyToStore;
|
this->wifiConfigSettings = copyToStore;
|
||||||
}
|
}
|
||||||
|
void Storage::LoadGovernorSettings()
|
||||||
|
{
|
||||||
|
std::filesystem::path path = this->dataRoot / GOVERNOR_SETTINGS_FILENAME;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (std::filesystem::is_regular_file(path))
|
||||||
|
{
|
||||||
|
std::ifstream f(path);
|
||||||
|
if (!f.is_open())
|
||||||
|
{
|
||||||
|
throw PiPedalException("Unable to write to " + ((std::string)path));
|
||||||
|
}
|
||||||
|
json_reader reader(f);
|
||||||
|
std::string governorSettings;
|
||||||
|
reader.read(&governorSettings);
|
||||||
|
this->governorSettings = governorSettings;
|
||||||
|
}
|
||||||
|
} catch (const std::exception&)
|
||||||
|
{
|
||||||
|
this->governorSettings = "performance";
|
||||||
|
}
|
||||||
|
this->wifiConfigSettings.valid_ = true;
|
||||||
|
|
||||||
|
}
|
||||||
void Storage::LoadWifiConfigSettings()
|
void Storage::LoadWifiConfigSettings()
|
||||||
{
|
{
|
||||||
std::filesystem::path path = this->dataRoot / WIFI_CONFIG_SETTINGS_FILENAME;
|
std::filesystem::path path = this->dataRoot / WIFI_CONFIG_SETTINGS_FILENAME;
|
||||||
@@ -1137,6 +1181,7 @@ uint64_t Storage::CopyPluginPreset(const std::string&pluginUri,uint64_t presetId
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JSON_MAP_BEGIN(CurrentPreset)
|
JSON_MAP_BEGIN(CurrentPreset)
|
||||||
JSON_MAP_REFERENCE(CurrentPreset,modified)
|
JSON_MAP_REFERENCE(CurrentPreset,modified)
|
||||||
JSON_MAP_REFERENCE(CurrentPreset,preset)
|
JSON_MAP_REFERENCE(CurrentPreset,preset)
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ private:
|
|||||||
bool isJackChannelSelectionValid = false;
|
bool isJackChannelSelectionValid = false;
|
||||||
JackChannelSelection jackChannelSelection;
|
JackChannelSelection jackChannelSelection;
|
||||||
WifiConfigSettings wifiConfigSettings;
|
WifiConfigSettings wifiConfigSettings;
|
||||||
|
std::string governorSettings = "performance";
|
||||||
public:
|
public:
|
||||||
Storage();
|
Storage();
|
||||||
void Initialize();
|
void Initialize();
|
||||||
@@ -85,6 +86,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
void LoadWifiConfigSettings();
|
void LoadWifiConfigSettings();
|
||||||
|
void LoadGovernorSettings();
|
||||||
void LoadBank(int64_t instanceId);
|
void LoadBank(int64_t instanceId);
|
||||||
const PedalBoard& GetCurrentPreset();
|
const PedalBoard& GetCurrentPreset();
|
||||||
void SaveCurrentPreset(const PedalBoard&pedalBoard);
|
void SaveCurrentPreset(const PedalBoard&pedalBoard);
|
||||||
@@ -116,6 +118,10 @@ public:
|
|||||||
void SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings);
|
void SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings);
|
||||||
WifiConfigSettings GetWifiConfigSettings();
|
WifiConfigSettings GetWifiConfigSettings();
|
||||||
|
|
||||||
|
void SetGovernorSettings(const std::string & governor);
|
||||||
|
std::string GetGovernorSettings() const;
|
||||||
|
|
||||||
|
|
||||||
void SaveCurrentPreset(const CurrentPreset ¤tPreset);
|
void SaveCurrentPreset(const CurrentPreset ¤tPreset);
|
||||||
bool RestoreCurrentPreset(CurrentPreset*pResult);
|
bool RestoreCurrentPreset(CurrentPreset*pResult);
|
||||||
|
|
||||||
|
|||||||
+35
-5
@@ -27,12 +27,13 @@
|
|||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include "PiPedalConfiguration.hpp"
|
#include "PiPedalConfiguration.hpp"
|
||||||
#include "Shutdown.hpp"
|
#include "ShutdownClient.hpp"
|
||||||
#include "CommandLineParser.hpp"
|
#include "CommandLineParser.hpp"
|
||||||
#include "Lv2SystemdLogger.hpp"
|
#include "Lv2SystemdLogger.hpp"
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include "HtmlHelper.hpp"
|
#include "HtmlHelper.hpp"
|
||||||
|
#include "Ipv6Helpers.hpp"
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
@@ -406,19 +407,26 @@ public:
|
|||||||
class InterceptConfig : public RequestHandler
|
class InterceptConfig : public RequestHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string response;
|
|
||||||
uint64_t maxUploadSize;
|
uint64_t maxUploadSize;
|
||||||
|
int portNumber;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InterceptConfig(int portNumber, uint64_t maxUploadSize)
|
InterceptConfig(int portNumber, uint64_t maxUploadSize)
|
||||||
: RequestHandler("/var/config.json"),
|
: RequestHandler("/var/config.json"),
|
||||||
maxUploadSize(maxUploadSize)
|
maxUploadSize(maxUploadSize),
|
||||||
|
portNumber(portNumber)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
std::string GetConfig(const std::string&fromAddress)
|
||||||
|
{
|
||||||
|
std::string linkLocalAddress = GetLinkLocalAddress(fromAddress);
|
||||||
|
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
|
|
||||||
s << "{ \"socket_server_port\": " << portNumber
|
s << "{ \"socket_server_port\": " << portNumber
|
||||||
<< ", \"socket_server_address\": \"*\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
<< ", \"socket_server_address\": \"" << linkLocalAddress << "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
||||||
response = s.str();
|
|
||||||
|
return s.str();
|
||||||
}
|
}
|
||||||
virtual ~InterceptConfig() {}
|
virtual ~InterceptConfig() {}
|
||||||
|
|
||||||
@@ -428,6 +436,17 @@ public:
|
|||||||
HttpResponse &res,
|
HttpResponse &res,
|
||||||
std::error_code &ec)
|
std::error_code &ec)
|
||||||
{
|
{
|
||||||
|
// intercepted. See the other overload.
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void head_response(
|
||||||
|
const std::string &fromAddress,
|
||||||
|
const uri&request_uri,
|
||||||
|
const HttpRequest &req,
|
||||||
|
HttpResponse &res,
|
||||||
|
std::error_code &ec)
|
||||||
|
{
|
||||||
|
std::string response = GetConfig(fromAddress);
|
||||||
res.set(HttpField::content_type, "application/json");
|
res.set(HttpField::content_type, "application/json");
|
||||||
res.set(HttpField::cache_control, "no-cache");
|
res.set(HttpField::cache_control, "no-cache");
|
||||||
res.setContentLength(response.length());
|
res.setContentLength(response.length());
|
||||||
@@ -440,6 +459,17 @@ public:
|
|||||||
HttpResponse &res,
|
HttpResponse &res,
|
||||||
std::error_code &ec)
|
std::error_code &ec)
|
||||||
{
|
{
|
||||||
|
// intercepted. see the other overload.
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void get_response(
|
||||||
|
const std::string&fromAddress,
|
||||||
|
const uri &request_uri,
|
||||||
|
const HttpRequest &req,
|
||||||
|
HttpResponse &res,
|
||||||
|
std::error_code &ec)
|
||||||
|
{
|
||||||
|
std::string response = GetConfig(fromAddress);
|
||||||
res.set(HttpField::content_type, "application/json");
|
res.set(HttpField::content_type, "application/json");
|
||||||
res.set(HttpField::cache_control, "no-cache");
|
res.set(HttpField::cache_control, "no-cache");
|
||||||
res.setContentLength(response.length());
|
res.setContentLength(response.length());
|
||||||
|
|||||||
@@ -53,5 +53,4 @@ template <typename T> class TypeDisplay;
|
|||||||
#include "lv2/parameters.lv2/parameters.h"
|
#include "lv2/parameters.lv2/parameters.h"
|
||||||
#include "lv2/units.lv2/units.h"
|
#include "lv2/units.lv2/units.h"
|
||||||
*/
|
*/
|
||||||
|
#include "ss.hpp"
|
||||||
#define SS(x) ( ((std::stringstream&)(std::stringstream() << x )).str())
|
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2022 Robin 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// usage: SS("xyz" << 123 << 45.6) returning a std::string rvalue.
|
||||||
|
#define SS(x) ( ((std::stringstream&)(std::stringstream() << x )).str())
|
||||||
Reference in New Issue
Block a user