Private
Public Access
Retry Hyperion indefinitely with autostart enabled
This commit is contained in:
1 parent
3160cf005b
commit
e720045bb1
13 files changed
+102
-33
No files matched your search
@@ -23,3 +23,5 @@ service/led-mapping.txt
|
|||||||
service/led-interpolation.txt
|
service/led-interpolation.txt
|
||||||
|
|
||||||
test-autostart
|
test-autostart
|
||||||
|
|
||||||
|
test-retry
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"id": "org.webosbrew.histogramhyperion",
|
"id": "org.webosbrew.histogramhyperion",
|
||||||
"version": "0.6.3",
|
"version": "0.6.4",
|
||||||
"type": "web",
|
"type": "web",
|
||||||
"title": "HyperDRM",
|
"title": "HyperDRM",
|
||||||
"appDescription": "Ambient lighting for webOS and Hyperion",
|
"appDescription": "Ambient lighting for webOS and Hyperion",
|
||||||
"iconUri": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/app/icon.png",
|
"iconUri": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/app/icon.png",
|
||||||
"sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM",
|
"sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM",
|
||||||
"rootRequired": true,
|
"rootRequired": true,
|
||||||
"ipkUrl": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/HyperDRM_0.6.3_arm.ipk",
|
"ipkUrl": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/HyperDRM_0.6.4_arm.ipk",
|
||||||
"ipkHash": {
|
"ipkHash": {
|
||||||
"sha256": "02f0ed2ff450573ad35807d6c75dc61840031826513c8cf2e71f7fb93332e0b1"
|
"sha256": "53762efd7e8d915d570fed96dbd1844d18ca825c21a9bc53f3aa28fea0f823ae"
|
||||||
},
|
},
|
||||||
"ipkSize": 1163846
|
"ipkSize": 1164794
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -25,7 +25,7 @@ Only the own service is modified. No Hue, LG library, driver or firmware binarie
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
The current package is [HyperDRM_0.6.3_arm.ipk](HyperDRM_0.6.3_arm.ipk). Install it using the TV's webOS/Homebrew package installation workflow.
|
The current package is [HyperDRM_0.6.4_arm.ipk](HyperDRM_0.6.4_arm.ipk). Install it using the TV's webOS/Homebrew package installation workflow.
|
||||||
|
|
||||||
Elevate the installed own service through Homebrew Channel:
|
Elevate the installed own service through Homebrew Channel:
|
||||||
|
|
||||||
@@ -41,9 +41,9 @@ The internal app/service IDs remain `org.webosbrew.histogramhyperion` and `org.w
|
|||||||
|
|
||||||
## Autostart
|
## Autostart
|
||||||
|
|
||||||
The app's **Autostart: On/Off** switch controls the own hook `/var/lib/webosbrew/init.d/60-histogramhyperion`. Homebrew Channel runs it during boot after service elevation. It retries start while the TV and Hyperion initialize, with up to 120 attempts separated by five seconds. The Homebrew failsafe can suppress boot hooks.
|
The app's **Autostart: On/Off** switch controls the own hook `/var/lib/webosbrew/init.d/60-histogramhyperion`. Homebrew Channel runs it during boot after service elevation. The boot hook waits until the native service accepts startup, then exits. With autostart enabled, the native service retries every five seconds without an attempt limit when startup fails or the Hyperion connection drops. It checks Hyperion before acquiring the LG capture resource. The Homebrew failsafe can suppress boot hooks.
|
||||||
|
|
||||||
**Stop** ends the current capture session and leaves the saved autostart preference unchanged. The hook is a symlink to `boot.sh` inside the service container. Removal leaves a harmless dangling link; the script also exits when its service target is absent. Turning autostart off removes the own hook and cancels waiting boot attempts. A foreign file or symlink at that path will not be overwritten.
|
**Stop** ends the current capture session and pauses retries until **Start** or the next service launch/boot; it leaves the saved autostart preference unchanged. The hook is a symlink to `boot.sh` inside the service container. Removal leaves a harmless dangling link; the script also exits when its service target is absent. Turning autostart off removes the own hook and cancels waiting boot attempts. A foreign file or symlink at that path will not be overwritten.
|
||||||
|
|
||||||
Boot log: `/var/lib/webosbrew/histogramhyperion-boot.log`.
|
Boot log: `/var/lib/webosbrew/histogramhyperion-boot.log`.
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ function display(result){
|
|||||||
else if(result.returnValue!==false)document.getElementById('status').textContent+=' · No current color output';
|
else if(result.returnValue!==false)document.getElementById('status').textContent+=' · No current color output';
|
||||||
if(result.blackBarDetection && result.running)document.getElementById('status').textContent+=result.letterboxDetected?' · Top/bottom black bars detected':' · Full-screen capture';
|
if(result.blackBarDetection && result.running)document.getElementById('status').textContent+=result.letterboxDetected?' · Top/bottom black bars detected':' · Full-screen capture';
|
||||||
if(result.spatialInterpolation)document.getElementById('status').textContent+=' · Smooth color transitions';
|
if(result.spatialInterpolation)document.getElementById('status').textContent+=' · Smooth color transitions';
|
||||||
|
if(result.retryScheduled)document.getElementById('status').textContent+=' · Retrying startup every 5 seconds';
|
||||||
|
if(result.retryPaused)document.getElementById('status').textContent+=' · Automatic retry paused until Start';
|
||||||
var box=document.getElementById('regions');box.textContent='';
|
var box=document.getElementById('regions');box.textContent='';
|
||||||
(result.regions||[]).forEach(function(rgb,index){var e=document.createElement('div');e.className='swatch';e.style.backgroundColor='rgb('+rgb.join(',')+')';e.title='Histogram '+index;box.appendChild(e);});
|
(result.regions||[]).forEach(function(rgb,index){var e=document.createElement('div');e.className='swatch';e.style.backgroundColor='rgb('+rgb.join(',')+')';e.title='Histogram '+index;box.appendChild(e);});
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
{"id": "org.webosbrew.histogramhyperion", "version": "0.6.3", "vendor": "Local development", "type": "web", "main": "index.html", "title": "HyperDRM", "icon": "icon.png", "resolution": "1920x1080", "disableBackHistoryAPI": true, "largeIcon": "large-icon.png", "appDescription": "Ambient lighting for webOS and Hyperion", "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM"}
|
{"id": "org.webosbrew.histogramhyperion", "version": "0.6.4", "vendor": "Local development", "type": "web", "main": "index.html", "title": "HyperDRM", "icon": "icon.png", "resolution": "1920x1080", "disableBackHistoryAPI": true, "largeIcon": "large-icon.png", "appDescription": "Ambient lighting for webOS and Hyperion", "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM"}
|
||||||
@@ -19,7 +19,7 @@ The capture initializer temporarily creates `/var/luna/preferences/vt_devmode` t
|
|||||||
|
|
||||||
No writes to signed system partitions. Writes outside the service container are limited to the own Homebrew autostart symlink, bounded boot log and transient developer marker. A guardian removes the own marker after initialization or process termination; a previously existing marker is preserved. Concurrent writes/power loss remain review considerations.
|
No writes to signed system partitions. Writes outside the service container are limited to the own Homebrew autostart symlink, bounded boot log and transient developer marker. A guardian removes the own marker after initialization or process termination; a previously existing marker is preserved. Concurrent writes/power loss remain review considerations.
|
||||||
|
|
||||||
The boot hook is a symlink to `service/boot.sh` in the installed container. The script checks for its executable and service metadata before acting, checks them again on every retry, and exits when the hook is disabled or the target is removed. Only an exact known legacy own hook is migrated; foreign files/symlinks are rejected. Logs are truncated at each invocation and per-attempt output is bounded.
|
The boot hook is a symlink to `service/boot.sh` in the installed container. The script checks for its executable and service metadata before acting, checks them again on every retry, and exits when the hook is disabled or the target is removed. Since 0.6.4 it delegates ongoing Hyperion recovery to the native service once startup or background retries are accepted. Only an exact known legacy own hook is migrated; foreign files/symlinks are rejected. Logs are truncated at each invocation and contain only startup/delegation/cancellation messages, so waiting has no unbounded boot-log growth.
|
||||||
|
|
||||||
## Source, licence and release
|
## Source, licence and release
|
||||||
|
|
||||||
@@ -41,3 +41,11 @@ Platform: LG G4, Rockhopper 10.2.2-57, SoC o24. Package: HyperDRM 0.6.1.
|
|||||||
- Restored the user's enabled autostart setting. No Hyperion configuration, PicCap or foreign hook was changed.
|
- Restored the user's enabled autostart setting. No Hyperion configuration, PicCap or foreign hook was changed.
|
||||||
|
|
||||||
This is an actual package lifecycle test, not a TV factory reset and not a cold boot.
|
This is an actual package lifecycle test, not a TV factory reset and not a cold boot.
|
||||||
|
|
||||||
|
## Persistent startup/reconnect retries (0.6.4)
|
||||||
|
|
||||||
|
With autostart enabled, the native service retries startup every five seconds without an attempt limit. Hyperion TCP availability and layout are checked before acquiring capture. The boot hook exits once native startup or background retries are accepted; it no longer owns the long-running reconnect loop. Manual Stop pauses retries for the current service session. Start or re-enabling autostart resumes them. Failed developer-marker cleanup blocks retries until manual intervention. Turning autostart off cancels automatic pending attempts.
|
||||||
|
|
||||||
|
ARM retry-state tests on the G4 passed 10000 delayed-start attempts, five-second pacing, manual Stop, disabling autostart, the cleanup safety block, bounded non-autostart source recovery and disconnect retry. Live tests temporarily stopped and restored Hyperion without changing configuration; automatic retry continued beyond six attempts (observed counts 10 and 11). Manual Stop left retryPaused:true and retryScheduled:false after Hyperion was restored.
|
||||||
|
|
||||||
|
A second live disconnect test confirmed retryScheduled:true while Hyperion was unavailable, followed by running:true and colorValid:true automatically within the six-second observation window after Hyperion restarted, without a new HyperDRM Start command.
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef HYPERDRM_RETRY_H
|
||||||
|
#define HYPERDRM_RETRY_H
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#define RETRY_DELAY_MS 5000
|
||||||
|
/* Continuous autostart retries and bounded manual source recovery. */
|
||||||
|
typedef struct {uint64_t due;unsigned attempts;bool automatic,paused,blocked;} RetryState;
|
||||||
|
static void retry_reset(RetryState *state){*state=(RetryState){0};}
|
||||||
|
static void retry_pause(RetryState *state){retry_reset(state);state->paused=true;}
|
||||||
|
static void retry_update(RetryState *state,bool enabled,bool running,uint64_t now){
|
||||||
|
bool previous=state->automatic;
|
||||||
|
state->automatic=enabled && !state->paused && !state->blocked;
|
||||||
|
if(previous && !state->automatic){state->due=0;state->attempts=0;}
|
||||||
|
if(state->automatic && !running && !state->due)state->due=now+RETRY_DELAY_MS;
|
||||||
|
}
|
||||||
|
static bool retry_take(RetryState *state,uint64_t now){
|
||||||
|
if(!state->due || now<state->due || state->paused || state->blocked)return false;
|
||||||
|
state->due=0;if(state->attempts<UINT_MAX)state->attempts++;return true;
|
||||||
|
}
|
||||||
|
static void retry_failure(RetryState *state,uint64_t now){
|
||||||
|
if(!state->paused && !state->blocked && (state->automatic || state->attempts<6))state->due=now+RETRY_DELAY_MS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+27
-18
@@ -23,6 +23,7 @@
|
|||||||
#include "interpolation.h"
|
#include "interpolation.h"
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
#include "autostart.h"
|
#include "autostart.h"
|
||||||
|
#include "retry.h"
|
||||||
#define SERVICE "org.webosbrew.histogramhyperion.service"
|
#define SERVICE "org.webosbrew.histogramhyperion.service"
|
||||||
#define PRIORITY 149
|
#define PRIORITY 149
|
||||||
typedef struct {int code;char *message;const char *file;int line;const char *func;void *padding;unsigned long magic;} LSError;
|
typedef struct {int code;char *message;const char *file;int line;const char *func;void *padding;unsigned long magic;} LSError;
|
||||||
@@ -59,8 +60,7 @@ static bool color_valid;
|
|||||||
static unsigned led_count;
|
static unsigned led_count;
|
||||||
static LedBlend *led_blends;
|
static LedBlend *led_blends;
|
||||||
static bool interpolation_enabled;
|
static bool interpolation_enabled;
|
||||||
static unsigned recovery_attempts;
|
static RetryState retries;
|
||||||
static uint64_t retry_at;
|
|
||||||
static uint64_t milliseconds(void){struct timespec t;clock_gettime(CLOCK_MONOTONIC,&t);return (uint64_t)t.tv_sec*1000+t.tv_nsec/1000000;}
|
static uint64_t milliseconds(void){struct timespec t;clock_gettime(CLOCK_MONOTONIC,&t);return (uint64_t)t.tv_sec*1000+t.tv_nsec/1000000;}
|
||||||
static char last_error[256];
|
static char last_error[256];
|
||||||
static volatile sig_atomic_t revoked,quitting;
|
static volatile sig_atomic_t revoked,quitting;
|
||||||
@@ -118,54 +118,63 @@ static void stop_capture(void){
|
|||||||
if(capture){vt_finish(capture);capture=NULL;}
|
if(capture){vt_finish(capture);capture=NULL;}
|
||||||
}
|
}
|
||||||
static bool respond(void *h,void *m,const char *s){if(!h||!m)return true;LSError e;error_init(&e);bool ok=reply(h,m,s,&e);error_free(&e);return ok;}
|
static bool respond(void *h,void *m,const char *s){if(!h||!m)return true;LSError e;error_init(&e);bool ok=reply(h,m,s,&e);error_free(&e);return ok;}
|
||||||
|
static bool start_failure(void *h,void *m,const char *message){
|
||||||
|
retry_update(&retries,boot_enabled() && geteuid()==0,false,milliseconds());
|
||||||
|
char json[512];snprintf(json,sizeof(json),"{\"returnValue\":false,\"errorText\":\"%s\",\"retryScheduled\":%s,\"retryBlocked\":%s}",message,retries.due?"true":"false",retries.blocked?"true":"false");
|
||||||
|
return respond(h,m,json);
|
||||||
|
}
|
||||||
static bool start(void *h,void *m,void *ctx){
|
static bool start(void *h,void *m,void *ctx){
|
||||||
(void)ctx;const char *p=m?payload(m):NULL;
|
(void)ctx;const char *p=m?payload(m):NULL;
|
||||||
if(p && strcmp(p,"{}")!=0)return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Start expects an empty object; endpoint is localhost:19444\"}");
|
if(p && strcmp(p,"{}")!=0)return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Start expects an empty object; endpoint is localhost:19444\"}");
|
||||||
|
if(m)retry_reset(&retries);
|
||||||
if(capture)return respond(h,m,"{\"returnValue\":true,\"running\":true}");
|
if(capture)return respond(h,m,"{\"returnValue\":true,\"running\":true}");
|
||||||
if(m){retry_at=0;recovery_attempts=0;}
|
|
||||||
frames=0;revoked=0;last_error[0]=0;lg_diagnostic[0]=0;
|
frames=0;revoked=0;last_error[0]=0;lg_diagnostic[0]=0;
|
||||||
if(!enter_developer_mode()){set_error("Developer initialization needs root. Elevate this own service through Homebrew Channel.");return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Root access is required for temporary LG developer initialization\"}");}
|
|
||||||
capture=vt_init(policy);
|
|
||||||
if(!leave_developer_mode()){stop_capture();set_error("Could not restore LG developer marker; check vt_devmode before retrying");return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Developer marker cleanup failed\"}");}
|
|
||||||
if(!capture){set_error("LG could not acquire the histogram capture resource. Check for another active capture source; no colors are being sent.");return respond(h,m,"{\"returnValue\":false,\"errorCode\":1,\"errorText\":\"LG refused histogram initialization. Another capture source may hold VT_CAPTURE. No colors are being sent.\"}");}
|
|
||||||
if(vt_preset(capture,0)!=0){stop_capture();set_error("LG histogram preset initialization failed");return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Histogram preset failed\"}");}
|
|
||||||
capture_preset=letterbox_mode=settling=0;pending_letterbox=-1;next_border_probe=0;
|
|
||||||
output=socket(AF_INET,SOCK_STREAM,0);
|
output=socket(AF_INET,SOCK_STREAM,0);
|
||||||
struct timeval timeout={1,0};
|
struct timeval timeout={1,0};
|
||||||
if(output>=0){setsockopt(output,SOL_SOCKET,SO_SNDTIMEO,&timeout,sizeof(timeout));setsockopt(output,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));}
|
if(output>=0){setsockopt(output,SOL_SOCKET,SO_SNDTIMEO,&timeout,sizeof(timeout));setsockopt(output,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));}
|
||||||
struct sockaddr_in a={.sin_family=AF_INET,.sin_port=htons(19444),.sin_addr={htonl(INADDR_LOOPBACK)}};
|
struct sockaddr_in a={.sin_family=AF_INET,.sin_port=htons(19444),.sin_addr={htonl(INADDR_LOOPBACK)}};
|
||||||
if(output<0||connect(output,(void*)&a,sizeof(a))!=0){stop_capture();set_error("Hyperion JSON server is unavailable on localhost:19444");return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Cannot connect to local Hyperion\"}");}
|
if(output<0||connect(output,(void*)&a,sizeof(a))!=0){stop_capture();set_error("Hyperion JSON server is unavailable on localhost:19444");return start_failure(h,m,"Cannot connect to local Hyperion");}
|
||||||
if(!read_layout()){stop_capture();set_error("Cannot read a valid LED layout from Hyperion");return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Cannot read Hyperion LED layout\"}");}
|
if(!read_layout()){stop_capture();set_error("Cannot read a valid LED layout from Hyperion");return start_failure(h,m,"Cannot read Hyperion LED layout");}
|
||||||
|
if(!enter_developer_mode()){stop_capture();set_error("Developer initialization needs root. Elevate this own service through Homebrew Channel.");return start_failure(h,m,"Root access is required for temporary LG developer initialization");}
|
||||||
|
capture=vt_init(policy);
|
||||||
|
if(!leave_developer_mode()){stop_capture();retries.blocked=true;set_error("Developer marker cleanup failed; manual intervention required");return start_failure(h,m,"Developer marker cleanup failed");}
|
||||||
|
if(!capture){stop_capture();set_error("LG refused histogram initialization");return start_failure(h,m,"LG refused histogram initialization. Another capture source may hold VT_CAPTURE.");}
|
||||||
|
if(vt_preset(capture,0)!=0){stop_capture();set_error("LG histogram preset initialization failed");return start_failure(h,m,"Histogram preset failed");}
|
||||||
|
capture_preset=letterbox_mode=settling=0;pending_letterbox=-1;next_border_probe=0;
|
||||||
|
retries.due=0;retries.attempts=0;
|
||||||
return respond(h,m,"{\"returnValue\":true,\"running\":true}");
|
return respond(h,m,"{\"returnValue\":true,\"running\":true}");
|
||||||
}
|
}
|
||||||
static bool stop(void *h,void *m,void *ctx){(void)ctx;retry_at=0;recovery_attempts=0;stop_capture();return respond(h,m,"{\"returnValue\":true,\"running\":false}");}
|
static bool stop(void *h,void *m,void *ctx){(void)ctx;retry_pause(&retries);stop_capture();return respond(h,m,"{\"returnValue\":true,\"running\":false}");}
|
||||||
static bool autostart(void *h,void *m,void *ctx){
|
static bool autostart(void *h,void *m,void *ctx){
|
||||||
(void)ctx;const char *p=m?payload(m):NULL;bool enabled;
|
(void)ctx;const char *p=m?payload(m):NULL;bool enabled;
|
||||||
if(p && strcmp(p,"{\"enabled\":true}")==0)enabled=true;
|
if(p && strcmp(p,"{\"enabled\":true}")==0)enabled=true;
|
||||||
else if(p && strcmp(p,"{\"enabled\":false}")==0)enabled=false;
|
else if(p && strcmp(p,"{\"enabled\":false}")==0)enabled=false;
|
||||||
else return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Expected enabled boolean\"}");
|
else return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Expected enabled boolean\"}");
|
||||||
if(geteuid()!=0 || !set_boot(enabled))return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Autostart could not be saved. Check own service root elevation and boot hook.\"}");
|
if(geteuid()!=0 || !set_boot(enabled))return respond(h,m,"{\"returnValue\":false,\"errorText\":\"Autostart could not be saved. Check own service root elevation and boot hook.\"}");
|
||||||
|
if(enabled)retry_reset(&retries);
|
||||||
|
retry_update(&retries,enabled,capture!=NULL,milliseconds());
|
||||||
return respond(h,m,enabled?"{\"returnValue\":true,\"autostart\":true}":"{\"returnValue\":true,\"autostart\":false}");
|
return respond(h,m,enabled?"{\"returnValue\":true,\"autostart\":true}":"{\"returnValue\":true,\"autostart\":false}");
|
||||||
}
|
}
|
||||||
static bool status(void *h,void *m,void *ctx){
|
static bool status(void *h,void *m,void *ctx){
|
||||||
(void)ctx;char json[4096],safe[512];size_t n=0;
|
(void)ctx;char json[4096],safe[512];size_t n=0;
|
||||||
for(size_t i=0;last_error[i] && n+2<sizeof(safe);i++){char c=last_error[i];if(c=='"'||c=='\\')safe[n++]='\\';if((unsigned char)c>=32)safe[n++]=c;}safe[n]=0;
|
for(size_t i=0;last_error[i] && n+2<sizeof(safe);i++){char c=last_error[i];if(c=='"'||c=='\\')safe[n++]='\\';if((unsigned char)c>=32)safe[n++]=c;}safe[n]=0;
|
||||||
int used=snprintf(json,sizeof(json),"{\"returnValue\":true,\"version\":\"0.6.3\",\"running\":%s,\"colorValid\":%s,\"frames\":%lu,\"endpoint\":\"127.0.0.1:19444\",\"priority\":%d,\"uid\":%u,\"drmVerified\":false,\"mappingVerified\":false,\"outputColor\":[%u,%u,%u],\"error\":\"%s\",\"regions\":[",capture?"true":"false",color_valid?"true":"false",frames,PRIORITY,(unsigned)geteuid(),sent_rgb[0],sent_rgb[1],sent_rgb[2],safe);
|
int used=snprintf(json,sizeof(json),"{\"returnValue\":true,\"version\":\"0.6.4\",\"running\":%s,\"colorValid\":%s,\"frames\":%lu,\"endpoint\":\"127.0.0.1:19444\",\"priority\":%d,\"uid\":%u,\"drmVerified\":false,\"mappingVerified\":false,\"outputColor\":[%u,%u,%u],\"error\":\"%s\",\"regions\":[",capture?"true":"false",color_valid?"true":"false",frames,PRIORITY,(unsigned)geteuid(),sent_rgb[0],sent_rgb[1],sent_rgb[2],safe);
|
||||||
for(int i=0;i<16;i++)used+=snprintf(json+used,sizeof(json)-used,"%s[%u,%u,%u]",i?",":"",rgb[i][0],rgb[i][1],rgb[i][2]);
|
for(int i=0;i<16;i++)used+=snprintf(json+used,sizeof(json)-used,"%s[%u,%u,%u]",i?",":"",rgb[i][0],rgb[i][1],rgb[i][2]);
|
||||||
used+=snprintf(json+used,sizeof(json)-used,"],\"ledCount\":%u,\"spatialOutput\":%s,\"blackPercent\":[",led_count,led_count?"true":"false");
|
used+=snprintf(json+used,sizeof(json)-used,"],\"ledCount\":%u,\"spatialOutput\":%s,\"blackPercent\":[",led_count,led_count?"true":"false");
|
||||||
for(int i=0;i<16;i++)used+=snprintf(json+used,sizeof(json)-used,"%s%u",i?",":"",black_percent[i]);
|
for(int i=0;i<16;i++)used+=snprintf(json+used,sizeof(json)-used,"%s%u",i?",":"",black_percent[i]);
|
||||||
snprintf(json+used,sizeof(json)-used,"],\"preset\":%u,\"saturationGain\":2.0,\"brightnessGain\":1.33,\"spatialInterpolation\":%s,\"blackBarDetection\":true,\"autostart\":%s,\"letterboxDetected\":%s}",capture_preset,interpolation_enabled?"true":"false",boot_enabled()?"true":"false",capture&&letterbox_mode?"true":"false");return respond(h,m,json);
|
snprintf(json+used,sizeof(json)-used,"],\"preset\":%u,\"saturationGain\":2.0,\"brightnessGain\":1.33,\"spatialInterpolation\":%s,\"blackBarDetection\":true,\"autostart\":%s,\"retryScheduled\":%s,\"retryPaused\":%s,\"retryBlocked\":%s,\"retryAttempts\":%u,\"letterboxDetected\":%s}",capture_preset,interpolation_enabled?"true":"false",boot_enabled()?"true":"false",retries.due?"true":"false",retries.paused?"true":"false",retries.blocked?"true":"false",retries.attempts,capture&&letterbox_mode?"true":"false");return respond(h,m,json);
|
||||||
}
|
}
|
||||||
static int tick(void *unused){
|
static int tick(void *unused){
|
||||||
(void)unused;
|
(void)unused;
|
||||||
if(!capture){
|
if(!capture){
|
||||||
if(retry_at && milliseconds()>=retry_at){
|
retry_update(&retries,boot_enabled() && geteuid()==0,false,milliseconds());
|
||||||
retry_at=0;recovery_attempts++;start(NULL,NULL,NULL);
|
if(retry_take(&retries,milliseconds())){
|
||||||
if(!capture && recovery_attempts<6)retry_at=milliseconds()+5000;
|
start(NULL,NULL,NULL);
|
||||||
|
if(!capture)retry_failure(&retries,milliseconds());
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(revoked){set_error("LG revoked capture; retrying initialization after source transition");stop_capture();recovery_attempts=0;retry_at=milliseconds()+5000;return 1;}
|
if(revoked){set_error("LG revoked capture; retrying initialization after source transition");stop_capture();retries.attempts=0;retry_failure(&retries,milliseconds());return 1;}
|
||||||
if(settling){settling--;return 1;}
|
if(settling){settling--;return 1;}
|
||||||
if(letterbox_mode && capture_preset==1 && milliseconds()>=next_border_probe){
|
if(letterbox_mode && capture_preset==1 && milliseconds()>=next_border_probe){
|
||||||
if(vt_preset(capture,0)!=0){set_error("Border probe preset failed");stop_capture();return 1;}
|
if(vt_preset(capture,0)!=0){set_error("Border probe preset failed");stop_capture();return 1;}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "retry.h"
|
||||||
|
int main(void){
|
||||||
|
RetryState state={0};uint64_t now=1000;
|
||||||
|
retry_update(&state,true,false,now);assert(state.due==6000);
|
||||||
|
assert(!retry_take(&state,5999));
|
||||||
|
for(unsigned i=0;i<10000;i++){
|
||||||
|
now=state.due;assert(retry_take(&state,now));retry_failure(&state,now);
|
||||||
|
assert(state.due==now+5000);
|
||||||
|
}
|
||||||
|
assert(state.attempts==10000);
|
||||||
|
retry_pause(&state);retry_update(&state,true,false,now+5000);
|
||||||
|
assert(state.paused && !state.due && !retry_take(&state,now+100000));
|
||||||
|
retry_reset(&state);retry_update(&state,true,false,now);
|
||||||
|
assert(state.due);retry_update(&state,false,false,now);assert(!state.due);
|
||||||
|
retry_update(&state,true,false,now);assert(state.due);
|
||||||
|
state.blocked=true;retry_update(&state,true,false,now);retry_failure(&state,now);assert(!state.due);
|
||||||
|
retry_reset(&state);retry_failure(&state,now);
|
||||||
|
for(unsigned i=0;i<6;i++){now=state.due;assert(retry_take(&state,now));retry_failure(&state,now);}
|
||||||
|
assert(state.attempts==6 && !state.due);
|
||||||
|
retry_reset(&state);retry_update(&state,true,true,now);assert(!state.due);
|
||||||
|
retry_update(&state,true,false,now);assert(state.due==now+5000);
|
||||||
|
puts("PASS: 10000 delayed-start attempts, five-second pacing, Stop pause, autostart off, safety block, bounded manual recovery, disconnect retry");
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
{"id": "org.webosbrew.histogramhyperion", "version": "0.6.3", "vendor": "Local development", "app": "org.webosbrew.histogramhyperion", "services": ["org.webosbrew.histogramhyperion.service"], "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM"}
|
{"id": "org.webosbrew.histogramhyperion", "version": "0.6.4", "vendor": "Local development", "app": "org.webosbrew.histogramhyperion", "services": ["org.webosbrew.histogramhyperion.service"], "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM"}
|
||||||
+4
-5
@@ -8,16 +8,15 @@ command -v luna-send >/dev/null 2>&1 || exit 0
|
|||||||
command -v timeout >/dev/null 2>&1 || exit 0
|
command -v timeout >/dev/null 2>&1 || exit 0
|
||||||
(
|
(
|
||||||
echo 'HyperDRM boot start requested'
|
echo 'HyperDRM boot start requested'
|
||||||
attempt=0
|
while [ -x "$TARGET" ] && [ -f "$SERVICE_DIR/services.json" ] && [ -L "$HOOK" ] && [ "$(readlink "$HOOK")" = "$SERVICE_DIR/boot.sh" ]; do
|
||||||
while [ -x "$TARGET" ] && [ -f "$SERVICE_DIR/services.json" ] && [ -L "$HOOK" ] && [ "$(readlink "$HOOK")" = "$SERVICE_DIR/boot.sh" ] && [ "$attempt" -lt 120 ]; do
|
|
||||||
result=$(timeout 12 luna-send -n 1 luna://org.webosbrew.histogramhyperion.service/start '{}' 2>&1)
|
result=$(timeout 12 luna-send -n 1 luna://org.webosbrew.histogramhyperion.service/start '{}' 2>&1)
|
||||||
case "$result" in
|
case "$result" in
|
||||||
*'"running":true'*) echo 'HyperDRM service started'; exit 0 ;;
|
*'"running":true'*) echo 'HyperDRM service started'; exit 0 ;;
|
||||||
|
*'"retryScheduled":true'*) echo 'HyperDRM service is retrying startup in the background'; exit 0 ;;
|
||||||
|
*'"retryBlocked":true'*) echo 'HyperDRM startup requires manual intervention'; exit 0 ;;
|
||||||
esac
|
esac
|
||||||
attempt=$((attempt + 1))
|
|
||||||
printf 'Attempt %s failed: %.512s\n' "$attempt" "$result"
|
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
echo 'HyperDRM boot start cancelled, target removed or retry limit reached'
|
echo 'HyperDRM boot start cancelled, target removed'
|
||||||
) >/var/lib/webosbrew/histogramhyperion-boot.log 2>&1 </dev/null &
|
) >/var/lib/webosbrew/histogramhyperion-boot.log 2>&1 </dev/null &
|
||||||
exit 0
|
exit 0
|
||||||
Binary file not shown.
Reference in new issue
Block a user