@ -33,12 +33,56 @@ var gpa: std.mem.Allocator = undefined;
/ / / all nm_xxx functions assume it is the case since they are invoked from lvgl c code .
/ / / all nm_xxx functions assume it is the case since they are invoked from lvgl c code .
var ui_mutex : std . Thread . Mutex = . { } ;
var ui_mutex : std . Thread . Mutex = . { } ;
/ / / current state of the GUI .
/ / / guarded by ui_mutex since some nm_xxx funcs branch based off of the state .
var state : enum {
var state : enum {
active , / / normal operational mode
active , / / normal operational mode
standby , / / idling
standby , / / idling
alert , / / draw user attention ; never go standby
alert , / / draw user attention ; never go standby
} = . active ;
} = . active ;
/ / / last report received from comm .
/ / / deinit ' ed at program exit .
/ / / while deinit and replace handle concurrency , field access requires holding mu .
var last_report : struct {
mu : std . Thread . Mutex = . { } ,
network : ? comm . Message . NetworkReport = null ,
bitcoind : ? comm . Message . BitcoindReport = null ,
fn deinit ( self : * @This ( ) ) void {
self . mu . lock ( ) ;
defer self . mu . unlock ( ) ;
if ( self . network ) | v | {
comm . free ( gpa , . { . network_report = v } ) ;
self . network = null ;
}
if ( self . bitcoind ) | v | {
comm . free ( gpa , . { . bitcoind_report = v } ) ;
self . bitcoind = null ;
}
}
fn replace ( self : * @This ( ) , new : anytype ) void {
self . mu . lock ( ) ;
defer self . mu . unlock ( ) ;
switch ( @TypeOf ( new ) ) {
comm . Message . NetworkReport = > {
if ( self . network ) | old | {
comm . free ( gpa , . { . network_report = old } ) ;
}
self . network = new ;
} ,
comm . Message . BitcoindReport = > {
if ( self . bitcoind ) | old | {
comm . free ( gpa , . { . bitcoind_report = old } ) ;
}
self . bitcoind = new ;
} ,
else = > @compileError ( " unhandled type: " + + @typeName ( @TypeOf ( new ) ) ) ,
}
}
} = . { } ;
/ / / the program runs until sigquit is true .
/ / / the program runs until sigquit is true .
/ / / set from sighandler or on unrecoverable comm failure with the daemon .
/ / / set from sighandler or on unrecoverable comm failure with the daemon .
var sigquit : std . Thread . ResetEvent = . { } ;
var sigquit : std . Thread . ResetEvent = . { } ;
@ -175,27 +219,29 @@ fn commThreadLoop() void {
/ / / the UI accordingly .
/ / / the UI accordingly .
/ / / holds ui mutex for most of the duration .
/ / / holds ui mutex for most of the duration .
fn commThreadLoopCycle ( ) ! void {
fn commThreadLoopCycle ( ) ! void {
const msg = try comm . read ( gpa , stdin ) ;
const msg = try comm . read ( gpa , stdin ) ; / / blocking
defer comm . free ( gpa , msg ) ;
ui_mutex . lock ( ) ; / / guards the state and all UI calls below
logger . debug ( " got msg: {s} " , . { @tagName ( msg ) } ) ;
ui_mutex . lock ( ) ; / / guards state and all UI calls below
defer ui_mutex . unlock ( ) ;
defer ui_mutex . unlock ( ) ;
switch ( state ) {
switch ( state ) {
. standby = > switch ( msg ) {
. standby = > switch ( msg ) {
. ping = > try comm . write ( gpa , stdout , comm . Message . pong ) ,
. ping = > try comm . write ( gpa , stdout , comm . Message . pong ) ,
else = > logger . debug ( " ignoring: in standby " , . { } ) ,
. network_report = > | v | last_report . replace ( v ) ,
. bitcoind_report = > | v | last_report . replace ( v ) ,
else = > logger . debug ( " ignoring {s}: in standby " , . { @tagName ( msg ) } ) ,
} ,
} ,
. active , . alert = > switch ( msg ) {
. active , . alert = > switch ( msg ) {
. ping = > try comm . write ( gpa , stdout , comm . Message . pong ) ,
. ping = > try comm . write ( gpa , stdout , comm . Message . pong ) ,
. network_report = > | report | {
. poweroff_progress = > | rep | {
updateNetworkStatus ( report ) catch | err | logger . err ( " updateNetworkStatus: {any} " , . { err } ) ;
ui . poweroff . updateStatus ( rep ) catch | err | logger . err ( " poweroff.updateStatus: {any} " , . { err } ) ;
comm . free ( gpa , msg ) ;
} ,
} ,
. poweroff_progress = > | report | {
. network_report = > | rep | {
ui . poweroff . updateStatus ( report ) catch | err | logger . err ( " poweroff.updateStatus: {any} " , . { err } ) ;
updateNetworkStatus ( rep ) catch | err | logger . err ( " updateNetworkStatus: {any} " , . { err } ) ;
last_report . replace ( rep ) ;
} ,
} ,
. bitcoind_report = > | rep | {
. bitcoind_report = > | rep | {
ui . bitcoin . updateTabPanel ( rep ) catch | err | logger . err ( " bitcoin.updateTabPanel: {any} " , . { err } ) ;
ui . bitcoin . updateTabPanel ( rep ) catch | err | logger . err ( " bitcoin.updateTabPanel: {any} " , . { err } ) ;
last_report . replace ( rep ) ;
} ,
} ,
else = > logger . warn ( " unhandled msg tag {s} " , . { @tagName ( msg ) } ) ,
else = > logger . warn ( " unhandled msg tag {s} " , . { @tagName ( msg ) } ) ,
} ,
} ,
@ -225,14 +271,23 @@ fn uiThreadLoop() void {
/ / wake up due to touch screen activity or wakeup event is set
/ / wake up due to touch screen activity or wakeup event is set
logger . info ( " waking up from sleep " , . { } ) ;
logger . info ( " waking up from sleep " , . { } ) ;
ui_mutex . lock ( ) ;
ui_mutex . lock ( ) ;
defer ui_mutex . unlock ( ) ;
if ( state = = . standby ) {
if ( state = = . standby ) {
state = . active ;
state = . active ;
comm . write ( gpa , stdout , comm . Message . wakeup ) catch | err | {
comm . write ( gpa , stdout , comm . Message . wakeup ) catch | err | {
logger . err ( " comm.write wakeup: {any} " , . { err } ) ;
logger . err ( " comm.write wakeup: {any} " , . { err } ) ;
} ;
} ;
lvgl . resetIdle ( ) ;
lvgl . resetIdle ( ) ;
last_report . mu . lock ( ) ;
defer last_report . mu . unlock ( ) ;
if ( last_report . network ) | rep | {
updateNetworkStatus ( rep ) catch | err | logger . err ( " updateNetworkStatus: {any} " , . { err } ) ;
}
if ( last_report . bitcoind ) | rep | {
ui . bitcoin . updateTabPanel ( rep ) catch | err | logger . err ( " bitcoin.updateTabPanel: {any} " , . { err } ) ;
}
}
}
ui_mutex . unlock ( ) ;
continue ;
continue ;
} ,
} ,
}
}
@ -331,6 +386,7 @@ pub fn main() anyerror!void {
try os . sigaction ( os . SIG . TERM , & sa , null ) ;
try os . sigaction ( os . SIG . TERM , & sa , null ) ;
sigquit . wait ( ) ;
sigquit . wait ( ) ;
last_report . deinit ( ) ;
logger . info ( " main terminated " , . { } ) ;
logger . info ( " main terminated " , . { } ) ;
}
}