터치 디스플레이 설정 관리 추가
This commit is contained in:
+328
-2
@@ -3478,6 +3478,308 @@ function custom_systemd_services(): array
|
||||
return $rows;
|
||||
}
|
||||
|
||||
function touch_display_bool(mixed $value): bool
|
||||
{
|
||||
return in_array((string)$value, ['1', 'true', 'yes', 'on'], true);
|
||||
}
|
||||
|
||||
function touch_display_file(string $kind): string
|
||||
{
|
||||
return $kind === 'cmdline' ? '/boot/firmware/cmdline.txt' : '/boot/firmware/config.txt';
|
||||
}
|
||||
|
||||
function touch_display_read_file(string $kind): string
|
||||
{
|
||||
$path = touch_display_file($kind);
|
||||
$content = @file_get_contents($path);
|
||||
return is_string($content) ? $content : '';
|
||||
}
|
||||
|
||||
function touch_display_backup_file(string $path): void
|
||||
{
|
||||
if (!is_file($path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$backup = $path . '.control-' . date('Ymd-His') . '.bak';
|
||||
if (function_exists('posix_geteuid') && posix_geteuid() === 0) {
|
||||
@copy($path, $backup);
|
||||
return;
|
||||
}
|
||||
|
||||
sh(['/bin/cp', '-a', $path, $backup], true, 5);
|
||||
}
|
||||
|
||||
function touch_display_write_file(string $path, string $content): void
|
||||
{
|
||||
if (function_exists('posix_geteuid') && posix_geteuid() === 0) {
|
||||
if (@file_put_contents($path, $content) === false) {
|
||||
throw new RuntimeException(basename($path) . ' 저장에 실패했습니다.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$tmp = sys_get_temp_dir() . '/control-touch-display-' . bin2hex(random_bytes(6));
|
||||
if (@file_put_contents($tmp, $content) === false) {
|
||||
throw new RuntimeException('임시 설정 파일 생성에 실패했습니다.');
|
||||
}
|
||||
@chmod($tmp, 0644);
|
||||
|
||||
$result = sh(['/bin/cp', '-f', $tmp, $path], true, 5);
|
||||
@unlink($tmp);
|
||||
if ($result['code'] !== 0) {
|
||||
throw new RuntimeException(trim($result['out']) !== '' ? trim($result['out']) : basename($path) . ' 저장에 실패했습니다.');
|
||||
}
|
||||
}
|
||||
|
||||
function touch_display_active_config_lines(string $config): array
|
||||
{
|
||||
return array_values(array_filter(
|
||||
preg_split('/\R/', $config) ?: [],
|
||||
static function (string $line): bool {
|
||||
$trimmed = trim($line);
|
||||
return $trimmed !== '' && !str_starts_with($trimmed, '#');
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
function touch_display_config_flag(array $lines, string $key): bool
|
||||
{
|
||||
foreach ($lines as $line) {
|
||||
if (preg_match('/^' . preg_quote($key, '/') . '\s*=\s*1\s*$/', $line)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function touch_display_overlay(array $lines): array
|
||||
{
|
||||
$overlay = [
|
||||
'enabled' => false,
|
||||
'params' => [],
|
||||
];
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if (!preg_match('/^dtoverlay\s*=\s*vc4-kms-dsi-7inch(?<params>(?:,.*)?)\s*$/', $line, $m)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$overlay['enabled'] = true;
|
||||
$params = trim((string)($m['params'] ?? ''), ',');
|
||||
foreach (array_filter(array_map('trim', explode(',', $params))) as $param) {
|
||||
if (str_contains($param, '=')) {
|
||||
[$key, $value] = array_map('trim', explode('=', $param, 2));
|
||||
$overlay['params'][$key] = $value;
|
||||
} else {
|
||||
$overlay['params'][$param] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $overlay;
|
||||
}
|
||||
|
||||
function touch_display_rotation(string $cmdline): int
|
||||
{
|
||||
if (preg_match('/(?:^|\s)video=DSI-1:\d+x\d+@\d+(?:\.\d+)?,rotate=(0|90|180|270)(?:\s|$)/', $cmdline, $m)) {
|
||||
return (int)$m[1];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function touch_display_status(): array
|
||||
{
|
||||
$connector = '/sys/class/drm/card0-DSI-1';
|
||||
$config = touch_display_read_file('config');
|
||||
$cmdline = touch_display_read_file('cmdline');
|
||||
$lines = touch_display_active_config_lines($config);
|
||||
$overlay = touch_display_overlay($lines);
|
||||
$params = $overlay['params'];
|
||||
|
||||
$statusPath = $connector . '/status';
|
||||
$modesPath = $connector . '/modes';
|
||||
$enabledPath = $connector . '/enabled';
|
||||
$dpmsPath = $connector . '/dpms';
|
||||
$modes = is_readable($modesPath)
|
||||
? array_values(array_filter(array_map('trim', file($modesPath, FILE_IGNORE_NEW_LINES) ?: [])))
|
||||
: [];
|
||||
|
||||
return [
|
||||
'connector' => 'DSI-1',
|
||||
'detected' => is_dir($connector),
|
||||
'connected' => trim((string)@file_get_contents($statusPath)) === 'connected',
|
||||
'status' => is_readable($statusPath) ? trim((string)@file_get_contents($statusPath)) : 'unknown',
|
||||
'enabled_state' => is_readable($enabledPath) ? trim((string)@file_get_contents($enabledPath)) : 'unknown',
|
||||
'dpms' => is_readable($dpmsPath) ? trim((string)@file_get_contents($dpmsPath)) : 'unknown',
|
||||
'modes' => $modes,
|
||||
'current_mode' => $modes[0] ?? '800x480',
|
||||
'framebuffer' => is_dir('/sys/class/graphics/fb0') ? 'fb0' : '-',
|
||||
'touch_input' => trim((string)shell_exec("for e in /sys/class/input/event*/device/name; do cat \"\$e\" 2>/dev/null; done | grep -i 'ft5x06' | head -n 1")) ?: '-',
|
||||
'config' => [
|
||||
'display_auto_detect' => touch_display_config_flag($lines, 'display_auto_detect'),
|
||||
'manual_overlay' => (bool)$overlay['enabled'],
|
||||
'display_enabled' => !touch_display_config_flag($lines, 'ignore_lcd'),
|
||||
'touch_enabled' => !touch_display_config_flag($lines, 'disable_touchscreen') && empty($params['disable_touch']),
|
||||
'rotation' => touch_display_rotation($cmdline),
|
||||
'touch_invx' => !empty($params['invx']) && (string)$params['invx'] !== '0',
|
||||
'touch_invy' => !empty($params['invy']) && (string)$params['invy'] !== '0',
|
||||
'touch_swapxy' => !empty($params['swapxy']) && (string)$params['swapxy'] !== '0',
|
||||
'touch_sizex' => is_numeric($params['sizex'] ?? null) ? (int)$params['sizex'] : 800,
|
||||
'touch_sizey' => is_numeric($params['sizey'] ?? null) ? (int)$params['sizey'] : 480,
|
||||
],
|
||||
'paths' => [
|
||||
'config' => touch_display_file('config'),
|
||||
'cmdline' => touch_display_file('cmdline'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function touch_display_comment_directives(string $config, array $patterns): string
|
||||
{
|
||||
$lines = preg_split('/\R/', $config) ?: [];
|
||||
$cleaned = [];
|
||||
$skipControlBlock = false;
|
||||
foreach ($lines as $line) {
|
||||
$trimmed = trim($line);
|
||||
if ($trimmed === '# Control touch display settings') {
|
||||
$skipControlBlock = true;
|
||||
continue;
|
||||
}
|
||||
if ($skipControlBlock) {
|
||||
if (
|
||||
$trimmed === ''
|
||||
|| preg_match('/^(display_auto_detect|ignore_lcd|disable_touchscreen)\s*=/', $trimmed)
|
||||
|| preg_match('/^dtoverlay\s*=\s*vc4-kms-dsi-7inch(?:,.*)?$/', $trimmed)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
$skipControlBlock = false;
|
||||
}
|
||||
$cleaned[] = $line;
|
||||
}
|
||||
$lines = $cleaned;
|
||||
|
||||
foreach ($lines as &$line) {
|
||||
$trimmed = trim($line);
|
||||
if ($trimmed === '' || str_starts_with($trimmed, '#')) {
|
||||
continue;
|
||||
}
|
||||
foreach ($patterns as $pattern) {
|
||||
if (preg_match($pattern, $trimmed)) {
|
||||
$line = '# control disabled: ' . $line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($line);
|
||||
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
function touch_display_set_config(array $input): array
|
||||
{
|
||||
$rotation = (int)($input['rotation'] ?? 0);
|
||||
if (!in_array($rotation, [0, 90, 180, 270], true)) {
|
||||
throw new RuntimeException('지원하지 않는 회전 값입니다.');
|
||||
}
|
||||
|
||||
$displayEnabled = touch_display_bool($input['display_enabled'] ?? '1');
|
||||
$touchEnabled = touch_display_bool($input['touch_enabled'] ?? '1');
|
||||
$invx = touch_display_bool($input['touch_invx'] ?? '0');
|
||||
$invy = touch_display_bool($input['touch_invy'] ?? '0');
|
||||
$swapxy = touch_display_bool($input['touch_swapxy'] ?? '0');
|
||||
$sizeX = max(100, min(4096, (int)($input['touch_sizex'] ?? 800)));
|
||||
$sizeY = max(100, min(4096, (int)($input['touch_sizey'] ?? 480)));
|
||||
$manualOverlay = touch_display_bool($input['manual_overlay'] ?? '0') || $invx || $invy || $swapxy || !$touchEnabled || $sizeX !== 800 || $sizeY !== 480;
|
||||
|
||||
$configPath = touch_display_file('config');
|
||||
$cmdlinePath = touch_display_file('cmdline');
|
||||
$config = touch_display_read_file('config');
|
||||
$cmdline = trim(touch_display_read_file('cmdline'));
|
||||
|
||||
if ($config === '' || $cmdline === '') {
|
||||
throw new RuntimeException('부팅 설정 파일을 읽을 수 없습니다.');
|
||||
}
|
||||
|
||||
$newConfig = touch_display_comment_directives($config, [
|
||||
'/^display_auto_detect\s*=/',
|
||||
'/^ignore_lcd\s*=/',
|
||||
'/^disable_touchscreen\s*=/',
|
||||
'/^dtoverlay\s*=\s*vc4-kms-dsi-7inch(?:,.*)?$/',
|
||||
]);
|
||||
|
||||
$append = [];
|
||||
$append[] = '';
|
||||
$append[] = '# Control touch display settings';
|
||||
if ($manualOverlay) {
|
||||
$params = ['vc4-kms-dsi-7inch'];
|
||||
if ($sizeX !== 800) {
|
||||
$params[] = 'sizex=' . $sizeX;
|
||||
}
|
||||
if ($sizeY !== 480) {
|
||||
$params[] = 'sizey=' . $sizeY;
|
||||
}
|
||||
if ($invx) {
|
||||
$params[] = 'invx';
|
||||
}
|
||||
if ($invy) {
|
||||
$params[] = 'invy';
|
||||
}
|
||||
if ($swapxy) {
|
||||
$params[] = 'swapxy';
|
||||
}
|
||||
if (!$touchEnabled) {
|
||||
$params[] = 'disable_touch';
|
||||
}
|
||||
$append[] = 'dtoverlay=' . implode(',', $params);
|
||||
} else {
|
||||
$append[] = 'display_auto_detect=1';
|
||||
}
|
||||
if (!$displayEnabled) {
|
||||
$append[] = 'ignore_lcd=1';
|
||||
}
|
||||
if (!$touchEnabled) {
|
||||
$append[] = 'disable_touchscreen=1';
|
||||
}
|
||||
$newConfig = rtrim($newConfig) . "\n" . implode("\n", $append) . "\n";
|
||||
|
||||
$newCmdline = preg_replace('/(?:^|\s)video=DSI-1:\d+x\d+@\d+(?:\.\d+)?,rotate=(?:0|90|180|270)(?=\s|$)/', '', $cmdline) ?? $cmdline;
|
||||
$newCmdline = trim(preg_replace('/\s+/', ' ', $newCmdline) ?? $newCmdline);
|
||||
if ($rotation !== 0) {
|
||||
$newCmdline .= ' video=DSI-1:800x480@60,rotate=' . $rotation;
|
||||
}
|
||||
$newCmdline .= "\n";
|
||||
|
||||
$changed = [];
|
||||
if ($newConfig !== $config) {
|
||||
touch_display_backup_file($configPath);
|
||||
touch_display_write_file($configPath, $newConfig);
|
||||
$changed[] = $configPath;
|
||||
}
|
||||
if ($newCmdline !== touch_display_read_file('cmdline')) {
|
||||
touch_display_backup_file($cmdlinePath);
|
||||
touch_display_write_file($cmdlinePath, $newCmdline);
|
||||
$changed[] = $cmdlinePath;
|
||||
}
|
||||
|
||||
add_fan_action(
|
||||
'touch_display_config',
|
||||
null,
|
||||
null,
|
||||
'rotation=' . $rotation . ', manual_overlay=' . ($manualOverlay ? '1' : '0') . ', display_enabled=' . ($displayEnabled ? '1' : '0') . ', touch_enabled=' . ($touchEnabled ? '1' : '0'),
|
||||
true
|
||||
);
|
||||
|
||||
return [
|
||||
'changed' => $changed,
|
||||
'reboot_required' => $changed !== [],
|
||||
'display' => touch_display_status(),
|
||||
];
|
||||
}
|
||||
|
||||
function collect_snapshot(bool $applyFan = true): array
|
||||
{
|
||||
if ($applyFan) {
|
||||
@@ -3653,9 +3955,12 @@ function collect_snapshot(bool $applyFan = true): array
|
||||
'history' => $history,
|
||||
'processes' => $processes,
|
||||
'custom_services' => custom_systemd_services(),
|
||||
'touch_display' => touch_display_status(),
|
||||
'fan_spike' => $fanSpike,
|
||||
'fan_spike_history' => fan_spike_history((int)setting_value('display.fan_notice_history_limit')),
|
||||
'settings' => settings_payload(),
|
||||
'settings' => array_merge(settings_payload(), [
|
||||
'touch_display' => touch_display_status(),
|
||||
]),
|
||||
];
|
||||
|
||||
return $snapshot;
|
||||
@@ -3689,7 +3994,9 @@ function control_api_dispatch(): void
|
||||
if ($action === 'settings') {
|
||||
json_out([
|
||||
'ok' => true,
|
||||
'data' => settings_payload(),
|
||||
'data' => array_merge(settings_payload(), [
|
||||
'touch_display' => touch_display_status(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -3717,6 +4024,25 @@ function control_api_dispatch(): void
|
||||
]);
|
||||
}
|
||||
|
||||
if ($action === 'touch_display_save') {
|
||||
$raw = (string)($_POST['display'] ?? '{}');
|
||||
$display = json_decode($raw, true);
|
||||
if (!is_array($display)) {
|
||||
json_out([
|
||||
'ok' => false,
|
||||
'error' => 'bad_display_settings',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$result = touch_display_set_config($display);
|
||||
$data = collect_snapshot(false);
|
||||
$data['touch_display_save'] = $result;
|
||||
json_out([
|
||||
'ok' => true,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($action === 'fan') {
|
||||
$mode = (string)($_POST['mode'] ?? 'auto');
|
||||
$pwm = max(0, min(255, (int)($_POST['pwm'] ?? 120)));
|
||||
|
||||
Reference in New Issue
Block a user