diff --git a/alConfig.c b/alConfig.c index c8ca3bb..4078bb3 100644 --- a/alConfig.c +++ b/alConfig.c @@ -441,6 +441,37 @@ int context,int caConnect,struct mainGroup *pmainGroup) return; } + if (strncmp(&buf[1],"BEEPCMD",7)==0) { + unsigned int start=8, end = strlen(buf) - 1; + + /* skip leading whitespace to find start of command */ + for(; start<=end && (buf[start]=='\t' || buf[start]==' '); start++) {} + + if(start>end) { + print_error(buf, "expected argument after BEEPCMD"); + return; + } + + /* back track to trim trailing whitespace */ + for(; end>=start && (buf[end]=='\0' || isspace(buf[end])); end--) {} + + if(end>start) { + if(psetup.beepCmd) + free(psetup.beepCmd); + psetup.beepCmd = malloc(end-start+2); + if(!psetup.beepCmd) { + print_error(buf, "Not enough memory for BEEPCMD"); + } else { + memcpy(psetup.beepCmd, &buf[start], end-start+1); + psetup.beepCmd[end-start+1] = '\0'; + } + } else { + print_error(buf, "Missing argument for BEEPCMD"); + } + + return; + } + if (strncmp(&buf[1],"HEARTBEATPV",11)==0) { /*HEARTBEATPV*/ if (pmainGroup->heartbeatPV.name) return; @@ -774,6 +805,8 @@ void alWriteConfig(char *filename,struct mainGroup *pmainGroup) if (!fw) return; if (psetup.beepSevr > 1) fprintf(fw,"$BEEPSEVERITY %s\n",alhAlarmSeverityString[psetup.beepSevr]); + if (psetup.beepCmd) + fprintf(fw,"$BEEPCMD %s\n", psetup.beepCmd); /*alWriteGroupConfig(fw,(SLIST *)&(pmainGroup->p1stgroup));*/ alWriteGroupConfig(fw,(SLIST *)pmainGroup); fclose(fw); diff --git a/alh.h b/alh.h index c0047d6..7e922d0 100644 --- a/alh.h +++ b/alh.h @@ -181,6 +181,7 @@ struct setup { char logFile[NAMEDEFAULT_SIZE]; /* alarm log file name */ char opModFile[NAMEDEFAULT_SIZE]; /* opMod log file name */ char saveFile[NAMEDEFAULT_SIZE]; /* save config file name */ + char *beepCmd; /* Optional command in place of X bell*/ Boolean silenceForever; /* 1 - beepoff forever is true */ short silenceOneHour; /* 1 - beepoff one hour is true */ short silenceCurrent; /* 1 - current beep on 0 - off */ diff --git a/os/default/alAudio.c b/os/default/alAudio.c index 6e58266..d72a4f6 100644 --- a/os/default/alAudio.c +++ b/os/default/alAudio.c @@ -18,9 +18,85 @@ * */ +#include #include +#include +#include +#include + #include "alh.h" +static pthread_mutex_t beep_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t beep_wake = PTHREAD_COND_INITIALIZER; +static pthread_once_t beep_setup = PTHREAD_ONCE_INIT; +/* states: -2 done, -1 shutdown, 0 idle, 1 playing, 2 request play */ +static int beeping = 0; +static pthread_t beeper; + +#define LOCK() assert(pthread_mutex_lock(&beep_lock)==0) +#define UNLOCK() assert(pthread_mutex_unlock(&beep_lock)==0) + +static void beeper_shutdown(void) +{ + /* request shutdown and spin until beeper thread stops */ + LOCK(); + beeping = -1; + while(beeping!=-2) { + UNLOCK(); + pthread_cond_broadcast(&beep_wake); + usleep(10000); /* 10ms */ + LOCK(); + } + /* thread is stopped now */ + free(psetup.beepCmd); + psetup.beepCmd = NULL; + + UNLOCK(); +} + +static void* beeper_thread(void* junk) +{ + LOCK(); + + atexit(&beeper_shutdown); + + while(beeping>=0) { + + assert(pthread_cond_wait(&beep_wake, &beep_lock)==0); + + if(beeping==2) { + beeping=1; + UNLOCK(); + + system(psetup.beepCmd); + + LOCK(); + /* be careful not to overwrite the shutdown command */ + if(beeping==1) + beeping=0; + } + } + UNLOCK(); + beeping=-2; + return NULL; +} + +static void setup(void) +{ + if(!psetup.beepCmd) + return; + + if(pthread_create(&beeper, NULL, &beeper_thread, NULL)) { + printf("Error creating beeper thread!\n"); + /* clear beepCmd so that future calls to alBeep() will + * call XBell(). + */ + free(psetup.beepCmd); + psetup.beepCmd = NULL; + return; + } +} + /* Audio device not implemented */ /****************************************************** @@ -28,9 +104,28 @@ ******************************************************/ int alBeep(Display *displayBB) { - /* system("play /path/to/beep.wav"); */ + pthread_once(&beep_setup, &setup); + + if(!psetup.beepCmd) { XBell(displayBB,0); return 0; + + } else { + LOCK(); + + /* wakeup for new command. + * also if still waiting for wakeup + * if beeper didn't start fast enough + * on the previous call. + */ + if(beeping==0 || beeping==2) { + beeping=2; + pthread_cond_broadcast(&beep_wake); + } + + UNLOCK(); + return 0; + } } diff --git a/test.alhConfig b/test.alhConfig index 2475da1..84c96c8 100644 --- a/test.alhConfig +++ b/test.alhConfig @@ -1,3 +1,4 @@ +$BEEPCMD sleep 5;date -R >> alhtest $BEEPSEVERITY MAJOR GROUP NULL JBA_TEST_MAIN_GROUP $COMMAND xload