Merge pull request #224 from rerdavies/dev

Merge v1.3.57 dev branch.
This commit is contained in:
Robin Davies
2024-10-13 22:30:49 -04:00
committed by GitHub
28 changed files with 395 additions and 97 deletions
+1 -1
View File
@@ -76,7 +76,7 @@
"request": "launch",
// Resolved by CMake Tools:
"program": "${command:cmake.launchTargetPath}",
"args": [ "/etc/pipedal/config", "/etc/pipedal/react", "-port", "0.0.0.0:8080" ],
"args": [ "/etc/pipedal/config", "/etc/pipedal/react", "-port", "0.0.0.0:8080", "-log-level","debug" ],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [
+2 -2
View File
@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.16.0)
project(pipedal
VERSION 1.3.56
VERSION 1.3.57
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
)
set (DISPLAY_VERSION "PiPedal v1.3.56-Release")
set (DISPLAY_VERSION "PiPedal v1.3.57-Release")
set (PACKAGE_ARCHITECTURE "arm64")
set (CMAKE_INSTALL_PREFIX "/usr/")
+2 -2
View File
@@ -6,13 +6,13 @@
<a href="https://rerdavies.github.io/pipedal/LicensePiPedal.html"><img src="https://img.shields.io/badge/MIT-MIT?label=license&color=%23808080"/></a>
<a href="https://github.com/rerdavies/pipedal/actions"><img src="https://img.shields.io/github/actions/workflow/status/rerdavies/pipedal/cmake.yml?branch=main"/></a>
Download:&nbsp;<a href='https://rerdavies.github.io/pipedal/download.html'>v1.3.56</a>
Download:&nbsp;<a href='https://rerdavies.github.io/pipedal/download.html'>v1.3.57</a>
Website:&nbsp;[https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
Documentation:&nbsp;[https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).
&nbsp;
#### NEW version 1.3.56 Release, providing [snapshots](https://rerdavies.github.io/pipedal/Snaphots.html), and a new Performance View. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
#### NEW version 1.3.57 Release, providing [snapshots](https://rerdavies.github.io/pipedal/Snaphots.html), and a new Performance View. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
&nbsp;
+1 -1
View File
@@ -10,7 +10,7 @@ You can optionally restrict the addresses on which PiPedal will respond by provi
To configure PiPedal to only accept connections on the Wi-Fi host access point:
sudo pipedalconfig --install --port 172.23.0.2:80
sudo pipedalconfig --install --port 192.168.60.1:80
--------
[<< Command-Line Configuration of PiPedal](CommandLine.md) | [Up](Documentation.md) | [Using LV2 Audio Plugins >>](UsingLv2Plugins.md)
+3 -3
View File
@@ -13,17 +13,17 @@ page_icon: img/Install4.jpg
Download the most recent Debian (.deb) package for your platform:
- [Raspberry Pi OS bookworm (64-bit) v1.3.56](https://github.com/rerdavies/pipedal/releases/download/)
- [Raspberry Pi OS bookworm (64-bit) v1.3.57](https://github.com/rerdavies/pipedal/releases/download/)
- [Ubuntu/Raspberry Pi OS bullseyeye (64-bit) v1.2.31](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb)
Version 1.3.56 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31.
Version 1.3.57 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31.
Install the package by running
```
sudo apt update
cd ~/Downloads
sudo apt-get install pipedal_1.3.56_arm64.deb
sudo apt-get install pipedal_1.3.57_arm64.deb
```
Adjust accordingly if you have downloaded v1.1.31.
+24
View File
@@ -1,5 +1,29 @@
# Release Notes
## PiPedal 1.3.57 Release
Features:
- dB readings displayed as text under the main VUs.
- Snapshot button title text now gets larger on large screens.
- Selection indicators on Snapshot buttons are more visible.
Bug fixes:
- Setting Dark Mode to follow system settings now tracks properly on the Android PiPedal Remote app.
- No longer crashes when using an audio adapter with mono input.
- Reload after a being suspended in the Android Client in order to ensure that controls and VUs continue to update. Not ideal, but when Android suspends a web app, web socket messages get silently discarded, so there's not much choice about it.
- GxTuner display now updates.
- Correct Escape and Enter key handling in search control of the Load Plugin dialog.
- Android remote: can connect when both Data connection and hotspot connection are active.
- Stack dumps get written to systemd log on segment violations (should make it easier to diagnose crashes in the field).
Known issues:
- To get the Android client to correctly follow system Dark Mode settings, you must update the Android app. You can work around the problem by explicitly selecting Light or Dark mode instead.
- To get the Android client to connect when both the hot-spot and data connections are active, you must update the Android app. In the meantime, you can work around the problem by going to Android Network Settings, and clicking to disconnect and then reconnect the hot-spot connection (which will disable the data connection).
The updated Android app has been submitted, and should show up on Google Play sometime tomorrow morning.
## PiPedal 1.3.56 Release
More snapshot problems.
+2 -2
View File
@@ -4,7 +4,7 @@
Download the most recent Debian (.deb) package for your platform:
- <a href="https://github.com/rerdavies/pipedal/releases/download/v1.3.56/pipedal_1.3.56_arm64.deb">Raspberry Pi OS Bookworm (64-bit) v1.3.56</a>
- <a href="https://github.com/rerdavies/pipedal/releases/download/v1.3.57/pipedal_1.3.57_arm64.deb">Raspberry Pi OS Bookworm (64-bit) v1.3.57</a>
Install the package by running
@@ -12,7 +12,7 @@ Install the package by running
```
sudo apt update
cd ~/Downloads
sudo apt-get install ./pipedal_1.3.56_arm64.deb
sudo apt-get install ./pipedal_1.3.57_arm64.deb
```
Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation.
+2 -2
View File
@@ -1,7 +1,7 @@
<img src="GithubBanner.png" width="100%"/>
<a href="Installing.html"><i>v1.3.56</i></a>
<a href="Installing.html"><i>v1.3.57</i></a>
&nbsp;
@@ -9,7 +9,7 @@ To download PiPedal, click [here](download.md).
To view PiPedal documentation, click [here](Documentation.md).
#### NEW version 1.3.56 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
#### NEW version 1.3.57 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
&nbsp;
+29 -8
View File
@@ -6,7 +6,8 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="PiPedal Guitar Pedals" />
<meta name="color-scheme" content="dark light"/> <!-- uses media queries in web views. -->
<meta name="description" content="PiPedal Guitar Pedals" />
<!--
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
-->
@@ -42,19 +43,39 @@
<script>
const androidHosted = !!(window.AndroidHost);
var colorScheme = localStorage.getItem("colorScheme");
if (androidHosted)
{
var hostColorScheme = window.AndroidHost.getThemePreference();
switch (hostColorScheme)
{
case 0:
colorScheme = "Light";
break;
case 1:
colorScheme = "Dark";
break;
case 2:
{
// use the host's interpretation of the current system night mode.
colorScheme = window.AndroidHost.isDarkTheme() ? "Dark": "Light";
}
break;
}
}
if (!colorScheme)
{
colorScheme = "Dark";
}
var darkMode = false;
var useSystem = false;
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
switch (localStorage.getItem("colorScheme")) {
switch (colorScheme) {
case null:
default:
if (androidHosted) {
useSystem = true;
} else {
darkMode = false;
}
darkMode = false;
break;
case "Light":
@@ -68,7 +89,7 @@
break;
}
if (useSystem) {
darkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
darkMode = prefersDark;
}
if (!darkMode) {
+4
View File
@@ -31,6 +31,7 @@ export interface AndroidHostInterface {
launchExternalUrl(url:string): boolean;
setThemePreference(theme: number): void;
getThemePreference(): number;
isDarkTheme?: ()=> boolean;
};
export class FakeAndroidHost implements AndroidHostInterface
@@ -43,6 +44,9 @@ export class FakeAndroidHost implements AndroidHostInterface
}
chooseNewDevice(): void {
}
isDarkTheme(): boolean {
return true;
}
setDisconnected(isDisconnected: boolean): void {
+1 -1
View File
@@ -103,7 +103,7 @@ const appStyles = (theme: Theme) => createStyles({
bottom: "0px",
opacity: 0.8,
background:
isDarkMode() ? "#222" : "#DDD",
isDarkMode() ? "#222" : "#EEE",
},
loadingContent: {
display: "block",
+28 -4
View File
@@ -17,7 +17,7 @@
// 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 { AndroidHostInterface } from "./AndroidHost";
import { AndroidHostInterface, getAndroidHost } from "./AndroidHost";
export enum ColorTheme {
Light,
@@ -25,7 +25,16 @@ export enum ColorTheme {
System
};
export function getEffectiveColorScheme(): ColorTheme {
let androidHost = (window as any).AndroidHost as AndroidHostInterface;
if (androidHost) {
if (androidHost.isDarkTheme)
return androidHost.isDarkTheme() ? ColorTheme.Dark: ColorTheme.Light;
return ColorTheme.Dark;
}
return getColorScheme();
}
export function getColorScheme(): ColorTheme {
let androidHost = (window as any).AndroidHost as AndroidHostInterface;
@@ -85,13 +94,28 @@ export function setColorScheme(value: ColorTheme): void {
localStorage.setItem("colorScheme", storageValue);
}
var gIsDarkTheme: boolean| undefined = undefined;
export function isDarkMode(): boolean {
if (gIsDarkTheme !== undefined)
{
return gIsDarkTheme;
}
var colorTheme = getColorScheme();
if (colorTheme === ColorTheme.System) {
let androidHost = getAndroidHost();
if (androidHost)
{
if (androidHost.isDarkTheme)
{
return gIsDarkTheme = androidHost.isDarkTheme();
}
return gIsDarkTheme = true;
}
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return true;
return gIsDarkTheme = true;
}
}
return colorTheme === ColorTheme.Dark;
return gIsDarkTheme = (colorTheme === ColorTheme.Dark);
}
+2 -1
View File
@@ -176,7 +176,8 @@ const GxTunerControl =
{
midiNote = value;
} else {
if (value < 65)
hz = value;
if (hz < 65)
{
hz = -1;
midiNote = -1;
+8
View File
@@ -607,6 +607,11 @@ export const LoadPluginDialog =
this.hSearchTimeout = undefined;
}
handleApplyFilter()
{
this.handleSearchStringReady();
}
cancelSearchTimeout()
{
if (this.hSearchTimeout) {
@@ -734,6 +739,9 @@ export const LoadPluginDialog =
onTextChanged={(text) => {
this.handleSearchStringChanged(text);
}}
onApplyFilter={() => {
this.handleApplyFilter();
}}
onClearFilterClick={() => {
if (this.state.search_string !== "") {
this.requestScrollTo();
+40 -19
View File
@@ -457,13 +457,39 @@ export class PiPedalModel //implements PiPedalModel
this.onSocketConnectionLost = this.onSocketConnectionLost.bind(this);
}
private expectDisconnectTimer?: NodeJS.Timeout = undefined;
cancelExpectDisconnectTimer()
{
if (this.expectDisconnectTimer) {
clearTimeout(this.expectDisconnectTimer);
}
}
startExpectDisconnectTimer()
{
this.cancelExpectDisconnectTimer();
// poll for access to a running pipedal server
this.expectDisconnectTimer = setTimeout(
async () => {
this.reconnectReason = ReconnectReason.Disconnected;
},
5 * 1000);
}
expectDisconnect(reason: ReconnectReason) {
this.cancelExpectDisconnectTimer();
this.reconnectReason = reason;
if (this.reconnectReason !== ReconnectReason.Disconnected)
{
this.startExpectDisconnectTimer();
}
}
onSocketReconnecting(retry: number, maxRetries: number): boolean {
this.cancelExpectDisconnectTimer();
if (this.isClosed) return false;
if (this.visibilityState.get() === VisibilityState.Hidden) return false;
//if (retry !== 0) {
switch (this.reconnectReason) {
case ReconnectReason.Disconnected:
@@ -515,7 +541,6 @@ export class PiPedalModel //implements PiPedalModel
}
onSocketMessage(header: PiPedalMessageHeader, body?: any) {
if (this.visibilityState.get() === VisibilityState.Hidden) return;
let message = header.message;
if (message === "onControlChanged") {
@@ -1187,7 +1212,6 @@ export class PiPedalModel //implements PiPedalModel
if (this.backgroundStateTimeout) {
clearTimeout(this.backgroundStateTimeout);
this.backgroundStateTimeout = undefined;
return;
}
if (this.state.get() === State.Background) {
console.log("Exiting background state.");
@@ -1200,17 +1224,19 @@ export class PiPedalModel //implements PiPedalModel
// on Android, delay entering background state by 180 seconds,
// since background management is more complicated. e.g. screen flips, and system upload dialogs.
if (this.isAndroidHosted()) {
if (this.backgroundStateTimeout) {
clearTimeout(this.backgroundStateTimeout);
}
this.backgroundStateTimeout = setTimeout(() => {
this.backgroundStateTimeout = undefined;
this.enterBackgroundState_();
}, 180000);
} else {
this.enterBackgroundState_();
}
// if (this.isAndroidHosted()) {
// yyyx;
// if (this.backgroundStateTimeout) {
// clearTimeout(this.backgroundStateTimeout);
// }
// this.backgroundStateTimeout = setTimeout(() => {
// this.backgroundStateTimeout = undefined;
// this.enterBackgroundState_();
// }, 180000);
// } else {
// this.enterBackgroundState_();
// }
this.enterBackgroundState_();
}
enterBackgroundState_() {
if (this.state.get() !== State.Background) {
@@ -1227,11 +1253,9 @@ export class PiPedalModel //implements PiPedalModel
switch (document.visibilityState) {
case "visible":
this.visibilityState.set(VisibilityState.Visible);
this.exitBackgroundState();
break;
case "hidden":
this.visibilityState.set(VisibilityState.Hidden);
this.enterBackgroundState();
break;
}
@@ -2424,9 +2448,6 @@ export class PiPedalModel //implements PiPedalModel
}
private handleNotifyPatchProperty(clientHandle: number, instanceId: number, propertyUri: string, jsonObject: any) {
// yyy this whole path is obsolete. We now get property change notifications
// always, since the entire pedalboard must track excactly.
// Review carefully.
let pedalboard = this.pedalboard.get();
let pedalboardItem = pedalboard.getItem(instanceId);
if (pedalboardItem) {
+3 -3
View File
@@ -94,7 +94,7 @@ const styles = (theme: Theme) => createStyles({
},
vuMeterL: {
position: "fixed",
paddingLeft: 12,
paddingLeft: 6,
paddingRight: 4,
paddingBottom: 24,
left: 0,
@@ -634,10 +634,10 @@ const PluginControlView =
return (
<div className={classes.frame}>
<div className={classes.vuMeterL}>
<VuMeter display="input" instanceId={pedalboardItem.instanceId} />
<VuMeter displayText={true} display="input" instanceId={pedalboardItem.instanceId} />
</div>
<div className={vuMeterRClass}>
<VuMeter display="output" instanceId={pedalboardItem.instanceId} />
<VuMeter displayText={true} display="output" instanceId={pedalboardItem.instanceId} />
</div>
<div className={gridClass} >
{
+16 -2
View File
@@ -17,7 +17,7 @@
// 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 React, { KeyboardEvent } from 'react';
import { Theme } from '@mui/material/styles';
import { WithStyles } from '@mui/styles';
import withStyles from '@mui/styles/withStyles';
@@ -39,6 +39,7 @@ interface SearchControlProps extends WithStyles<typeof styles> {
onTextChanged: (searchString: string) => void;
onClick: () => void;
onClearFilterClick: () => void;
onApplyFilter: () => void;
inputRef?: React.RefObject<HTMLInputElement>;
showSearchIcon?: boolean
@@ -66,6 +67,17 @@ const SearchControl = withStyles(styles, { withTheme: true })(
}
return this.defaultInputRef;
}
onKeyDown(ev: KeyboardEvent)
{
ev.stopPropagation(); // don't let the ENTER key propagate propagate the enclosing dialog Enter key handler.
if (ev.key === "Enter")
{
this.props.onApplyFilter();
} else if (ev.key === "Escape")
{
this.props.onClearFilterClick();
}
}
componentDidUpdate(oldProps: SearchControlProps) {
if (oldProps.collapsed ?? false !== this.props.collapsed ?? false) {
let inputRef = this.getInputRef();
@@ -96,7 +108,9 @@ const SearchControl = withStyles(styles, { withTheme: true })(
)
}
<Input spellCheck={false} style={{
<Input spellCheck={false}
onKeyDown={(ev)=>{this.onKeyDown(ev);}}
style={{
flex: "1 1", visibility: (this.props.collapsed ?? false) ? "collapse" : "visible", marginRight: 12, height: 32,
}}
inputRef={this.getInputRef()}
+1 -1
View File
@@ -86,7 +86,7 @@ export default class SnapshotDialog extends ResizeResponsiveComponent<SnapshotDi
}
getFullScreen() {
return window.innerHeight < 450;
return window.innerHeight < 450 || window.innerWidth < 450;
}
onWindowSizeChanged(width: number, height: number): void {
this.setState(
+1 -1
View File
@@ -211,7 +211,7 @@ export default class UpdateDialog extends ResizeResponsiveComponent<UpdateDialog
<Typography noWrap variant="body2" color="textSecondary" >
Update version:
</Typography>
<Typography noWrap variant="body2" color="textSecondary" >
<Typography noWrap variant="body2" color="textSecondary" style={{ marginLeft: 16 }} >
{updateRelease.upgradeVersionDisplayName}
</Typography>
</div>
+84 -5
View File
@@ -20,8 +20,7 @@
import React, { Component } from 'react';
import { Theme } from '@mui/material/styles';
import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import {createStyles,withStyles} from '@mui/styles';
import { PiPedalModel, State,PiPedalModelFactory, VuUpdateInfo, VuSubscriptionHandle } from './PiPedalModel';
@@ -55,13 +54,15 @@ class TelltaleState {
telltaleDb: number = MIN_DB;
lastTelltaleTime: number = 0;
telltaleHoldTime: number = 0;
telltaleHoldValue: number = MIN_DB;
reset() : void {
this.telltaleHoldTime = 0;
this.lastTelltaleTime = 0;
this.telltaleDb = MIN_DB;
this.telltaleHoldValue = MIN_DB;
}
getValue(currentDb: number): number {
getTelltaleHoldValue(currentDb: number): number {
let t = new Date().getTime();
let holdValue: number;
@@ -78,6 +79,7 @@ class TelltaleState {
}
}
}
this.telltaleHoldValue = holdValue;
if (currentDb > holdValue) {
this.telltaleDb = currentDb;
@@ -93,7 +95,7 @@ class TelltaleState {
const LEFT_X = BORDER_THICKNESS;
const RIGHT_X = BORDER_THICKNESS + + CHANNEL_WIDTH + BORDER_THICKNESS;
const styles = ({ palette }: Theme) => createStyles({
const styles = (theme: Theme) => createStyles({
frame: {
position: "relative",
width: CHANNEL_WIDTH + 2*BORDER_THICKNESS,
@@ -114,6 +116,23 @@ const styles = ({ palette }: Theme) => createStyles({
background: "black",
overflow: "hidden",
},
monoTextFrame: {
display: "flex",flexFlow: "column nowrap", alignItems: "center", textAlign: "center"
},
stereoTextFrame: {
display: "flex",flexFlow: "column nowrap", alignItems: "center", textAlign: "center"
},
vuTextFrame: {
color: theme.palette.text.secondary,
display: "table-cell",
position: "relative",
marginTop: 4,
textAlign: "center",
width: 20, height: 16,
fontSize: "11px",
justifyContent: "center",
alignItems: "center"
},
redFrameL: {
position: "absolute",
top: "100%",
@@ -189,6 +208,7 @@ interface VuMeterProps extends WithStyles<typeof styles> {
instanceId: number;
display: "input" | "output";
theme: Theme;
displayText?: boolean;
}
interface VuMeterState {
@@ -213,6 +233,7 @@ export const VuMeter =
class extends Component<VuMeterProps, VuMeterState>
{
divRef: React.RefObject<HTMLDivElement> = React.createRef();
textRef: React.RefObject<HTMLDivElement> = React.createRef();
model: PiPedalModel;
yZero: number;
@@ -240,6 +261,35 @@ export const VuMeter =
vuInfo?: VuUpdateInfo;
requesttedStereoState: boolean = false;
updateText(telltaleDb: number)
{
if (this.textRef.current) {
let displayValue: string;
if (telltaleDb <= MIN_DB)
{
displayValue = "-";
} else {
let iDb = Math.round(telltaleDb);
if (iDb > 0)
{
displayValue = "+" + Math.round(telltaleDb).toString() + "\u00A0"
} else if (iDb < 0) {
displayValue = Math.round(telltaleDb).toString() + "\u00A0";
} else {
if (telltaleDb === 0) {
displayValue = "0";
} else if (telltaleDb > 0)
{
displayValue = "+0\u00A0";
} else {
displayValue = "-0\u00A0";
}
}
}
this.textRef.current.innerText = displayValue;
}
}
onVuChanged(vuInfo: VuUpdateInfo): void {
let value: number;
let valueR: number;
@@ -291,6 +341,15 @@ export const VuMeter =
};
this.updateChannel(vuData, this.telltaleStateR);
}
if (this.props.displayText)
{
if (this.state.isStereo)
{
this.updateText(Math.max(this.telltaleStateL.telltaleHoldValue,this.telltaleStateR.telltaleHoldValue));
} else {
this.updateText(this.telltaleStateL.telltaleHoldValue);
}
}
}
resetTelltales() {
@@ -319,7 +378,7 @@ export const VuMeter =
vuData.redDiv.style.top = y + "px";
}
}
let dbTelltale = telltaleState.getValue(db);
let dbTelltale = telltaleState.getTelltaleHoldValue(db);
let yTelltale = dbToY(dbTelltale);
if (yTelltale < this.yZero) {
@@ -381,8 +440,28 @@ export const VuMeter =
render() {
let displayText = this.props.displayText??false;
let classes = this.props.classes;
if (displayText)
{
return (
<div className={this.state.isStereo? classes.stereoTextFrame: classes.monoTextFrame}>
{
this.renderVus()
}
<div ref={this.textRef} className={classes.vuTextFrame}
/>
</div>
);
} else {
return this.renderVus();
}
}
renderVus() {
let classes = this.props.classes;
if (!this.state.isStereo) {
return (<div className={classes.frame} ref={this.divRef}
>
+17 -6
View File
@@ -5,6 +5,10 @@ set (CMAKE_INSTALL_PREFIX "/usr/")
set (USE_PCH 1)
set (ENABLE_BACKTRACE 1)
set (USE_SANITIZE true)
set(CXX_STANDARD 20)
include(FindPkgConfig)
@@ -96,9 +100,6 @@ endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set (USE_SANITIZE true)
if (!ENABLE_VST3)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wno-psabi -DARCHITECTURE=${CPACK_SYSTEM_NAME}")
else()
@@ -119,10 +120,17 @@ if (CMAKE_BUILD_TYPE MATCHES Debug)
endif()
elseif(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
message(STATUS "RelWithgDebInfo build")
#set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "" )
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG" )
else()
message(STATUS "Release build")
#set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "" )
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG" )
endif()
if (ENABLE_BACKTRACE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
if (${DEBIAN_ARCHITECTURE} MATCHES arm64)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -funwind-tables")
endif()
endif()
@@ -292,6 +300,9 @@ add_executable(pipedald
)
target_include_directories(pipedald PRIVATE ${PIPEDAL_INCLUDES})
target_compile_definitions(pipedald PRIVATE "ENABLE_BACKTRACE=${ENABLE_BACKTRACE}")
target_link_libraries(pipedald PRIVATE PiPedalCommon
${PIPEDAL_LIBS}
@@ -627,7 +638,7 @@ add_executable(pipedalconfig
)
target_link_libraries(pipedalconfig PRIVATE PiPedalCommon pthread atomic uuid stdc++fs
target_link_libraries(pipedalconfig PRIVATE PiPedalCommon pthread atomic uuid stdc++fs
)
add_executable(pipedal_latency_test
+35 -2
View File
@@ -44,6 +44,9 @@
#include <grp.h>
#include "ofstream_synced.hpp"
#include <pwd.h>
#include <unistd.h>
#define P2PD_DISABLED
#if JACK_HOST
@@ -88,6 +91,29 @@ namespace fs = std::filesystem;
#define REMOVE_OLD_SERVICE 0 // Grandfathering: whether to remove the old shutdown service (now pipedaladmind)
#define OLD_SHUTDOWN_SERVICE "pipedalshutdownd"
void changeUserShell(const char* username, const char* newShell) {
struct passwd* pw;
struct passwd p;
char buf[1024];
pw = getpwnam(username);
if (pw == nullptr) {
throw std::runtime_error("User not found");
}
if (strcmp(pw->pw_shell,newShell) == 0) {
return;
}
std::string args = SS("/usr/sbin/usermod -s " << newShell << " " << username);
if (silentSysExec(args.c_str()) != EXIT_SUCCESS)
{
cout << "Failed to set shell for " << username << endl;
}
}
fs::path GetServiceFileName(const std::string &serviceName)
{
return fs::path(SERVICE_PATH) / (serviceName + ".service");
@@ -926,7 +952,7 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
try
{
// apply policy changes we dropped into the polkit configuration files (allows pipedal_d to use NetworkManager dbus apis).
silentSysExec(SYSTEMCTL_BIN " restart polkit");
silentSysExec(SYSTEMCTL_BIN " restart polkit.service");
DeployVarConfig();
@@ -994,7 +1020,7 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
if (!userExists(SERVICE_ACCOUNT_NAME))
{
if (sysExec(USERADD_BIN " " SERVICE_ACCOUNT_NAME " -g " SERVICE_GROUP_NAME " -m --home /var/pipedal/home -N -r") != EXIT_SUCCESS)
if (sysExec(USERADD_BIN " " SERVICE_ACCOUNT_NAME " -g " SERVICE_GROUP_NAME " -s /usr/sbin/nologin -m --home /var/pipedal/home -N -r") != EXIT_SUCCESS)
{
// throw std::runtime_error("Failed to create service account.");
}
@@ -1007,6 +1033,13 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
// add to netdev group
sysExec(USERMOD_BIN " -a -G " NETDEV_GROUP_NAME " " SERVICE_ACCOUNT_NAME);
try {
changeUserShell(SERVICE_ACCOUNT_NAME, "/usr/sbin/nologon");
} catch (const std::exception&e)
{
cout << "Error: Can't set user shell for pipedal_d. " << e.what() << std::endl;
}
// create and configure /var directory.
fs::path varDirectory("/var/pipedal");
+17 -13
View File
@@ -467,7 +467,7 @@ void HotspotManagerImpl::onReload()
case State::HotspotConnected:
default:
// force a reload.
StopHotspot();
StopHotspot();
SetState(State::Monitoring);
MaybeStartHotspot();
return;
@@ -861,28 +861,32 @@ void HotspotManagerImpl::StartHotspot()
settings["ipv4"]["method"] = "shared";
settings["ipv6"]["method"] = "shared";
settings["ipv6"]["addr-gen-mode"] = 1; // "stable-privacy";
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
// Create connection
settings["ipv4"]["method"] = sdbus::Variant(std::string("shared"));
//settings["ipv6"]["method"] = sdbus::Variant(std::string("ignore"));
// Create connection
settings["ipv4"]["method"] = sdbus::Variant(std::string("shared"));
// settings["ipv6"]["method"] = sdbus::Variant(std::string("ignore"));
settings["ipv4"]["address-data"] = sdbus::Variant(std::vector<std::map<std::string, sdbus::Variant>>{{{"address", sdbus::Variant("192.168.60.1")},
{"prefix", sdbus::Variant(uint32_t(24))}}});
// settings["ipv4"]["gateway'"] = sdbus::Variant(std::string("192.168.60.1"));
settings["ipv4"]["dhcp-send-hostname"] = sdbus::Variant(true);
settings["ipv4"]["dhcp-hostname"] = sdbus::Variant("raspberrypi");
// settings["ipv4"]["dhcp-options"] = sdbus::Variant(std::vector<std::string>{
// "option:classless-static-route,192.168.60.0/24,0.0.0.0,0.0.0.0/0,192.168.60.1"});
// "option:classless-static-route,192.168.60.0/23,0.0.0.0,0.0.0.0/0,192.168.60.1"});
// settings["ipv4"]["dhcp-options"] = sdbus::Variant(std::vector<std::string>{
// "option:classless-static-route,192.168.60.0/23,192.168.60.1"});
settings["ipv4"]["route-data"] = sdbus::Variant(std::vector<std::map<std::string, sdbus::Variant>>{{
{"dest", sdbus::Variant("192.168.4.0")},
{"prefix", sdbus::Variant(uint32_t(24))},
{"metric", sdbus::Variant((uint32_t)99)}
}});
////////////////////////////////////////////////////////////
// settings["ipv6"]["addr-gen-mode"] = "stable-privacy";
settings["ipv6"]["address-data"] = sdbus::Variant(std::vector<std::map<std::string, sdbus::Variant>>{
{{"address", sdbus::Variant("fdd2:e477:7b37:5b09::1")},
{"prefix", sdbus::Variant(uint32_t(64))}}});
settings["ipv6"]["gateway"] = sdbus::Variant("fdd2:e477:7b37:5b09::1");
std::map<std::string, sdbus::Variant> options;
options["persist"] = "disk";
+10 -10
View File
@@ -544,9 +544,9 @@ p2p configuration:
dnsmaqsq.d/30-pipedal-p2p.conf:
interface=p2p-wlan0-0
dhcp-range=p2p-wlan0,173.24.0.3,172.23.0.127,1h
dhcp-range=p2p-wlan0,173.24.0.3,192.168.60.127,1h
domain=local
address=/pipedal.local/172.23.0.2
address=/pipedal.local/192.168.60.2
except-interface=eth0
except-interface=wlan0
@@ -556,8 +556,8 @@ except-interface=lo
dhcpcd.conf:
======
interface p2p-wlan0-0
static ip_address=172.24.0.1/16
domain_name_servers=172.24.0.1
static ip_address=192.168.60.1/16
domain_name_servers=192.168.60.1
Watch resolv.conf to make sure we don't lose DNS servers.
************************************************************************************/
@@ -672,8 +672,8 @@ static void ConfigDhcpcdForP2p()
// dhcpcd.conf:
// ======
// interface p2p-wlan0-0
// static ip_address=172.24.0.1/24
// domain_name_server=172.24.0.1
// static ip_address=192.168.60.1/24
// domain_name_server=192.168.60.1
int line = dhcpcd.GetLineThatStartsWith("hostname");
std::string hostNameLine;
@@ -691,8 +691,8 @@ static void ConfigDhcpcdForP2p()
{
line = dhcpcd.GetLineCount();
// interface p2p-wlan0-0
// static ip_address=172.24.0.1/16 (trying int on .1.)
// domain_name_server=172.24.0.1
// static ip_address=192.168.60.1/16 (trying int on .1.)
// domain_name_server=192.168.60.1
dhcpcd.InsertLine(line++, "interface p2p-wlan0-0");
dhcpcd.InsertLine(line++, " static ip_address=" P2P_INTERFACE_ADDR);
@@ -705,8 +705,8 @@ static void ConfigDhcpcdForP2p()
line = dhcpcd.GetLineCount();
}
// interface p2p-wlan0-0
// static ip_address=172.24.0.1/16 (trying int on .1.)
// domain_name_server=172.24.0.1
// static ip_address=192.168.60.1/16 (trying int on .1.)
// domain_name_server=192.168.60.1
dhcpcd.InsertLine(line++, SS("allowinterfaces p2p-" << GetWifiConfigWlanAddress() << "-*").c_str());
dhcpcd.InsertLine(line++, "static ip_address=" P2P_INTERFACE_ADDR);
+56 -2
View File
@@ -27,7 +27,7 @@
#include "ServiceConfiguration.hpp"
#include "AvahiService.hpp"
#include "WebServerConfig.hpp"
#include <execinfo.h>
#include "PiPedalSocket.hpp"
#include "PluginHost.hpp"
#include <boost/system/error_code.hpp>
@@ -87,11 +87,50 @@ static void AsanCheck()
exit(EXIT_FAILURE);
}
#if ENABLE_BACKTRACE
void segvHandler(int sig) {
void *array[10];
// Get void*'s for all entries on the stack
size_t size;
size = backtrace(array, 10);
// Print out all the frames to stderr
const char *message = "Error: SEGV signal received.\n";
write(STDERR_FILENO,message,strlen(message));
backtrace_symbols_fd(array+2, size-2, STDERR_FILENO);
_exit(EXIT_FAILURE);
}
static void EnableBacktrace()
{
signal(SIGSEGV, segvHandler);
}
#endif
static bool TryGetLogLevel(const std::string&strLogLevel,LogLevel*result)
{
if (strLogLevel == "debug") {*result= LogLevel::Debug; return true;}
if (strLogLevel == "info") {*result= LogLevel::Info; return true;}
if (strLogLevel == "warning") {*result= LogLevel::Warning; return true;}
if (strLogLevel == "error") { *result= LogLevel::Error; return true;}
*result = LogLevel::Info;
return false;
}
int main(int argc, char *argv[])
{
#ifndef WIN32
umask(002); // newly created files in /var/pipedal get 775-ish permissions, which improves debugging/live-service interaction.
umask(002); // newly created files in /var/pipedal get 7cd75-ish permissions, which improves debugging/live-service interaction.
#endif
#if ENABLE_BACKTRACE
EnableBacktrace();
#endif
// Check command line arguments.
@@ -99,12 +138,14 @@ int main(int argc, char *argv[])
bool error = false;
bool systemd = false;
bool testExtraDevice = false;
std::string logLevel;
std::string portOption;
CommandLineParser parser;
parser.AddOption("-h", &help);
parser.AddOption("--help", &help);
parser.AddOption("-systemd", &systemd);
parser.AddOption("-log-level",&logLevel);
parser.AddOption("-port", &portOption);
parser.AddOption("-test-extra-device", &testExtraDevice); // advertise two different devices (for testing multi-device connect)
@@ -139,6 +180,7 @@ int main(int argc, char *argv[])
<< "Options:\n"
<< " -systemd: Log to systemd journals instead of to the console.\n"
<< " -port: Port to listen on e.g. 80, or 0.0.0.0:80\n"
<< " -log-level: (debug|info|warning|error)"
<< "Example:\n"
<< " pipedald /etc/pipedal/config /etc/pipedal/react -port 80 \n"
"\n"
@@ -180,6 +222,18 @@ int main(int argc, char *argv[])
}
Lv2Log::log_level(configuration.GetLogLevel());
if (logLevel.length() != 0)
{
LogLevel lv2LogLevel;
if (TryGetLogLevel(logLevel,&lv2LogLevel))
{
Lv2Log::log_level(lv2LogLevel);
} else {
Lv2Log::error(SS("Invalid log level: " << logLevel));
return EXIT_SUCCESS; // indicate to systemd that we don't want a restart.
}
}
if (portOption.length() != 0)
{
+2 -2
View File
@@ -3,9 +3,9 @@
interface=p2p-${WLAN}-*
#disable dns, dhcp only.a"
port=0
dhcp-range=172.23.0.20,172.23.0.127,15m
dhcp-range=192.168.60.20,192.168.60.127,15m
domain=local
address=/pipedal-p2p.local/172.23.0.2
address=/pipedal-p2p.local/192.168.60.2
except-interface=eth0
except-interface=${WLAN}
+2 -2
View File
@@ -3,9 +3,9 @@ server=8.8.4.4
interface=p2p-wlan0-0
dhcp-range=172.23.0.3,172.23.0.127,15m
dhcp-range=192.168.60.3,192.168.60.127,15m
domain=local
address=/pipedal.local/172.23.0.2
address=/pipedal.local/192.168.60.2
except-interface=eth0
except-interface=wlan0
+2 -2
View File
@@ -1,9 +1,9 @@
# PiPedal dnsmasq settings for p2p
#disable dns, dhcp only."
port=0
dhcp-range=172.23.0.3,172.23.0.127,15m
dhcp-range=192.168.60.3,192.168.60.127,15m
domain=local
address=/pipedal-p2p.local/172.23.0.2
address=/pipedal-p2p.local/192.168.60.2
# defensive. Not actually required.
except-interface=eth0