static int serialReadExact (WVIEW_MEDIUM *med, void *bfr, int len, int msTimeout) { int rval, cumTime = 0, index = 0; uint64_t readTime; uint8_t *ptr = (uint8_t *)bfr; while (index < len && cumTime < msTimeout) { readTime = radTimeGetMSSinceEpoch (); rval = read (med->fd, &ptr[index], len - index); if (rval < 0) { if (errno != EINTR && errno != EAGAIN) { return ERROR; } } else { index += rval; } readTime = radTimeGetMSSinceEpoch () - readTime; cumTime += (int)readTime; if (index < len && cumTime < msTimeout) { readTime = radTimeGetMSSinceEpoch (); radUtilsSleep (9); readTime = radTimeGetMSSinceEpoch () - readTime; cumTime += (int)readTime; } } return ((index == len) ? len : ERROR); }
static void portDTRToggle (int fd, int msec) { struct termios tty, old; tcgetattr (fd, &tty); tcgetattr (fd, &old); cfsetospeed (&tty, B0); cfsetispeed (&tty, B0); tcsetattr (fd, TCSANOW, &tty); if (msec > 0) { radUtilsSleep (msec); } tcsetattr (fd, TCSANOW, &old); }
static int executeScript (WVIEW_ALARM *alarm) { int retVal; char *args[5]; char path[_MAX_PATH]; char type[64]; char thresh[64]; char trigVal[64]; wvstrncpy (path, alarm->scriptToRun, _MAX_PATH); args[0] = path; sprintf (type, "%d", alarm->type); args[1] = type; sprintf (thresh, "%.3f", alarm->bound); args[2] = thresh; sprintf (trigVal, "%.3f", alarm->triggerValue); args[3] = trigVal; args[4] = 0; retVal = fork (); if (retVal == -1) { return -1; } else if (retVal == 0) { // we are the child! if (execv (path, args) == -1) { radMsgLog(PRI_HIGH, "executeScript: execv(%s) failed: %s", path, strerror(errno)); exit(-1); } exit(0); } else { // we are the parent, pause a bit to let the script run // and avoid a process "storm" radUtilsSleep (50); // 50 ms } return 0; }
static int serialInit (WVIEW_MEDIUM *med, char *deviceName) { MEDIUM_SERIAL *serialWork = (MEDIUM_SERIAL *)med->workData; // ... open our serial channel med->fd = open (deviceName, serialWork->openFlags); if (med->fd == -1) { radMsgLog (PRI_CATASTROPHIC, "Serial device %s failed to open: %s", deviceName, strerror(errno)); return ERROR; } #ifdef HAVE_FLOCK if (flock (med->fd, LOCK_EX) < 0) #else struct flock lock = {0}; lock.l_type = F_WRLCK; if (fcntl(med->fd, F_SETLKW, &lock) < 0) #endif { if (errno == EOPNOTSUPP) { radMsgLog(PRI_MEDIUM, "serial device locking not supported by OS for %s", deviceName); } else { radMsgLog (PRI_CATASTROPHIC, "Serial device %s locked by other program!", deviceName); return ERROR; } } // configure it serialWork->portInit (med->fd); tcflush (med->fd, TCIFLUSH); tcflush (med->fd, TCOFLUSH); // Save the device name: strncpy(serialWork->device, deviceName, WVIEW_STRING2_SIZE); radUtilsSleep (1); return OK; }
static int serialRestart (WVIEW_MEDIUM *med) { MEDIUM_SERIAL *work = (MEDIUM_SERIAL*)med->workData; serialExit(med); radMsgLog (PRI_HIGH, "serialRestart: attempting restart"); while ((!wviewdIsExiting()) && (serialInit(med, work->device) == ERROR)) { radMsgLog (PRI_HIGH, "serialRestart: restart failed"); radUtilsSleep(5000); radMsgLog (PRI_HIGH, "serialRestart: retrying restart"); } if (!wviewdIsExiting()) { radMsgLog (PRI_HIGH, "serialRestart: recovered"); } return OK; }
// Autobaud the TWI station: // Returns the baudrate or ERROR: int twiConfig(WVIEWD_WORK *pWork) { int baudIndex; radMsgLog (PRI_STATUS, "==> Detecting TWI communication settings:"); // now autobaud the station: for (baudIndex = 0; baudIndex < TWI_NUMBER_BAUDS; baudIndex ++) { radMsgLog (PRI_STATUS, "==> Trying %s-8-N-1...", BaudNames[baudIndex]); // setup the port serialPortConfig(pWork->medium.fd, BaudRates[baudIndex]); tcflush (pWork->medium.fd, TCIFLUSH); tcflush (pWork->medium.fd, TCOFLUSH); // bump the DTR line so the station will not hang in certain scenarios if (pWork->stationToggleDTR) { portDTRToggle (pWork->medium.fd, 100); } // try to communicate: twiProtocolWriteLineToStation(pWork, "R", FALSE); radUtilsSleep (100); if (twiProtocolReadLine(pWork) == OK) { radMsgLog (PRI_STATUS, "==> Yes!"); radMsgLog (PRI_STATUS, "==> Found TWI at %s-8-N-1", BaudNames[baudIndex]); return (int)BaudRates[baudIndex]; } else { radMsgLog (PRI_STATUS, "==> No"); } } radMsgLog (PRI_HIGH, "==> TWI autodetect failed!!"); return ERROR; }
// station-supplied function to indicate data is available on the station // interface medium (serial or ethernet) - // It is the responsibility of the station interface to read the data from the // medium and process appropriately. The data does not have to be read within // the context of this function, but may be used to stimulate a state machine. // -- Synchronous -- // // Returns: N/A // void stationDataIndicate (WVIEWD_WORK *work) { int retVal, done = FALSE; if (virtualProtocolDataIndicate(work) == ERROR_ABORT) { // We need to try to reconnect: radMsgLog (PRI_HIGH, "VIRTUAL: remote station lost - retrying..."); virtualProtocolExit(work); (*(work->medium.exit))(&work->medium); while (! done && ! work->exiting) { retVal = RestoreConnection(work); if (retVal == ERROR_ABORT) { radMsgLog (PRI_HIGH, "VIRTUAL: restore connection failed - exiting"); radProcessSetExitFlag(); done = TRUE; } else if (retVal == OK) { radMsgLog (PRI_HIGH, "VIRTUAL: restore connection success"); virtualProtocolInit(work); done = TRUE; } else { radMsgLog (PRI_HIGH, "VIRTUAL: try again in 15 seconds to restore connection."); radUtilsSleep(15000); } } } return; }
static void processCWOP () { RADSOCK_ID socket; time_t ntime; struct tm *gmTime; char cwopBuffer[256], login[64]; int length = 0; char *serv; int port; volatile WVIEW_MSG_ARCHIVE_NOTIFY Notify; memcpy ((void*)&Notify, (void*)&cwopWork.ArchiveMsg, sizeof(WVIEW_MSG_ARCHIVE_NOTIFY)); // format the CWOP data ntime = time (NULL); gmTime = gmtime (&ntime); length = sprintf (cwopBuffer, "%s>APRS,TCPXX*,qAX,%s:@", cwopWork.callSign, cwopWork.callSign); length += sprintf (&cwopBuffer[length], "%2.2d%2.2d%2.2dz", gmTime->tm_mday, gmTime->tm_hour, gmTime->tm_min); length += sprintf (&cwopBuffer[length], "%s/%s", cwopWork.latitude, cwopWork.longitude); // check for any wind registered if (Notify.wspeed < 0) { length += sprintf (&cwopBuffer[length], "_..."); } else { length += sprintf (&cwopBuffer[length], "_%3.3d", Notify.winddir); } length += sprintf (&cwopBuffer[length], "/%3.3d", Notify.wspeed); length += sprintf (&cwopBuffer[length], "g%3.3d", Notify.hiwspeed); if (Notify.temp < 0) { if (((Notify.temp * (-1)) % 10) >= 5) { Notify.temp -= 10; } length += sprintf (&cwopBuffer[length], "t-%2.2d", (Notify.temp * (-1))/10); } else { if ((Notify.temp % 10) >= 5) { Notify.temp += 10; } length += sprintf (&cwopBuffer[length], "t%3.3d", Notify.temp/10); } length += sprintf (&cwopBuffer[length], "P%3.3d", Notify.rainDay); if (Notify.humidity >= 0 && Notify.humidity <= 100) { length += sprintf (&cwopBuffer[length], "h%2.2d", Notify.humidity % 100); } length += sprintf (&cwopBuffer[length], "b%5.5d", (int)(10 * wvutilsConvertINHGToHPA((float)Notify.altimeter/1000.0))); sprintf (&cwopBuffer[length], ".%s", wvutilsCreateCWOPVersion(globalWviewVersionStr)); // connect to the CWOP server - try the primary then secondary then tertiary socket = radSocketClientCreate (cwopWork.server1, cwopWork.portNo1); if (socket == NULL) { statusUpdateMessage("CWOP-connect: failed to connect to server"); statusIncrementStat(CWOP_STATS_CONNECT_ERRORS); wvutilsLogEvent (PRI_MEDIUM, "CWOP-connect: failed to connect to %s:%d", cwopWork.server1, cwopWork.portNo1); // try the secondary server socket = radSocketClientCreate (cwopWork.server2, cwopWork.portNo2); if (socket == NULL) { statusUpdateMessage("CWOP-connect: failed to connect to server"); statusIncrementStat(CWOP_STATS_CONNECT_ERRORS); wvutilsLogEvent (PRI_MEDIUM, "CWOP-connect: failed to connect to %s:%d", cwopWork.server2, cwopWork.portNo2); // try the tertiary server socket = radSocketClientCreate (cwopWork.server3, cwopWork.portNo3); if (socket == NULL) { // we are all out of luck this time! statusUpdateMessage("CWOP-connect: failed to connect to server"); statusIncrementStat(CWOP_STATS_CONNECT_ERRORS); wvutilsLogEvent (PRI_MEDIUM, "CWOP-connect: failed to connect to %s:%d", cwopWork.server3, cwopWork.portNo3); radMsgLog (PRI_HIGH, "CWOP-connect: failed to connect to all 3 APRS servers!"); return; } else { serv = cwopWork.server3; port = cwopWork.portNo3; } } else { serv = cwopWork.server2; port = cwopWork.portNo2; } } else { serv = cwopWork.server1; port = cwopWork.portNo1; } // wait 1 second ... radUtilsSleep (1000); // transmit the data sprintf (login, "user %6s pass %d vers %s", cwopWork.callSign, (int)getPasscode(cwopWork.callSign), globalWviewVersionStr); length = strlen (login); login[length] = 0x0D; // tack on the CR and LF login[length+1] = 0x0A; login[length+2] = 0; if (radSocketWriteExact (socket, login, length + 2) != (length + 2)) { statusUpdateMessage("CWOP-error: failed to login to server"); radMsgLog (PRI_HIGH, "CWOP-error: %d: failed to login to %s:%d!", errno, serv, port); radSocketDestroy (socket); return; } // wait 3 seconds ... radUtilsSleep (3000); // write the data record wvutilsLogEvent (PRI_STATUS, "CWOP-send: %s", cwopBuffer); length = strlen (cwopBuffer); cwopBuffer[length] = 0x0D; // tack on the CR and LF cwopBuffer[length+1] = 0x0A; cwopBuffer[length+2] = 0; if (radSocketWriteExact (socket, cwopBuffer, length + 2) != (length + 2)) { statusUpdateMessage("CWOP-error: failed to write to server"); radMsgLog (PRI_HIGH, "CWOP-error: %d: failed to write to %s:%d!", errno, serv, port); radSocketDestroy (socket); return; } statusIncrementStat(CWOP_STATS_PKTS_SENT); // wait 3 more seconds ... radUtilsSleep (3000); // close connection and cleanup radSocketDestroy (socket); return; }
/* ... the main entry point for the wvcwopd process */ int main (int argc, char *argv[]) { void (*alarmHandler)(int); int retVal; FILE *pidfile; int iValue; double dValue; const char* sValue; int runAsDaemon = TRUE; if (argc > 1) { if (!strcmp(argv[1], "-f")) { runAsDaemon = FALSE; } } memset (&cwopWork, 0, sizeof (cwopWork)); /* ... initialize some system stuff first */ retVal = cwopSysInit (&cwopWork); if (retVal == ERROR) { radMsgLogInit (PROC_NAME_CWOP, FALSE, TRUE); radMsgLog (PRI_CATASTROPHIC, "wvcwopd init failed!"); radMsgLogExit (); exit (1); } else if (retVal == ERROR_ABORT) { exit (2); } /* ... call the global radlib system init function */ if (radSystemInit (WVIEW_SYSTEM_ID) == ERROR) { radMsgLogInit (PROC_NAME_CWOP, TRUE, TRUE); radMsgLog (PRI_CATASTROPHIC, "radSystemInit failed!"); radMsgLogExit (); exit (1); } /* ... call the radlib process init function */ if (radProcessInit (PROC_NAME_CWOP, cwopWork.fifoFile, PROC_NUM_TIMERS_CWOP, runAsDaemon, // TRUE for daemon msgHandler, evtHandler, NULL) == ERROR) { printf ("\nradProcessInit failed: %s\n\n", PROC_NAME_CWOP); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } cwopWork.myPid = getpid (); pidfile = fopen (cwopWork.pidFile, "w"); if (pidfile == NULL) { radMsgLog (PRI_CATASTROPHIC, "lock file create failed!"); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } fprintf (pidfile, "%d", getpid ()); fclose (pidfile); alarmHandler = radProcessSignalGetHandler (SIGALRM); radProcessSignalCatchAll (defaultSigHandler); radProcessSignalCatch (SIGALRM, alarmHandler); radProcessSignalRelease(SIGABRT); // get our configuration values if (wvconfigInit(FALSE) == ERROR) { radMsgLog (PRI_CATASTROPHIC, "wvconfigInit failed!"); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } // Is the CWOP daemon enabled? iValue = wvconfigGetBooleanValue(configItem_ENABLE_CWOP); if (iValue == ERROR || iValue == 0) { wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "CWOP daemon is NOT enabled - exiting..."); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } // get the wview verbosity setting if (wvutilsSetVerbosity (WV_VERBOSE_WVCWOPD) == ERROR) { wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "wvutilsSetVerbosity failed!"); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } // get the APRS call sign sValue = wvconfigGetStringValue(configItemCWOP_APRS_CALL_SIGN); if (sValue == NULL) { // we can't do without this! wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "%s failed!", configItemCWOP_APRS_CALL_SIGN); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { wvstrncpy (cwopWork.callSign, sValue, sizeof(cwopWork.callSign)); if (sValue[strlen(sValue)-1] >= '0' && sValue[strlen(sValue)-1] <= '9') { cwopWork.callSignOffset = atoi(&sValue[strlen(sValue)-1]); } else { cwopWork.callSignOffset = (sValue[strlen(sValue)-1] % 10); } cwopWork.callSignOffset %= 10; } // get the primary APRS server sValue = wvconfigGetStringValue(configItemCWOP_APRS_SERVER1); if (sValue == NULL) { // we can't do without this! wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "%s failed!", configItemCWOP_APRS_SERVER1); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { wvstrncpy (cwopWork.server1, sValue, sizeof(cwopWork.server1)); } // get the primary APRS port number iValue = wvconfigGetINTValue(configItemCWOP_APRS_PORTNO1); if (iValue < 0) { // we can't do without this! wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "%s failed!", configItemCWOP_APRS_PORTNO1); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { cwopWork.portNo1 = iValue; } // get the secondary APRS server sValue = wvconfigGetStringValue(configItemCWOP_APRS_SERVER2); if (sValue == NULL) { // we can't do without this! wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "%s failed!", configItemCWOP_APRS_SERVER2); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { wvstrncpy (cwopWork.server2, sValue, sizeof(cwopWork.server2)); } // get the primary APRS port number iValue = wvconfigGetINTValue(configItemCWOP_APRS_PORTNO2); if (iValue < 0) { // we can't do without this! wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "%s failed!", configItemCWOP_APRS_PORTNO2); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { cwopWork.portNo2 = iValue; } // get the tertiary APRS server sValue = wvconfigGetStringValue(configItemCWOP_APRS_SERVER3); if (sValue == NULL) { // we can't do without this! wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "%s failed!", configItemCWOP_APRS_SERVER3); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { wvstrncpy (cwopWork.server3, sValue, sizeof(cwopWork.server3)); } // get the primary APRS port number iValue = wvconfigGetINTValue(configItemCWOP_APRS_PORTNO3); if (iValue < 0) { // we can't do without this! wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "%s failed!", configItemCWOP_APRS_PORTNO3); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { cwopWork.portNo3 = iValue; } // get the fine pitch latitude that APRS requires sValue = wvconfigGetStringValue(configItemCWOP_LATITUDE); if (sValue == NULL) { // we can't do without this! wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "%s failed!", configItemCWOP_LATITUDE); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { wvstrncpy (cwopWork.latitude, sValue, sizeof(cwopWork.latitude)); } // get the fine pitch longitude that APRS requires sValue = wvconfigGetStringValue(configItemCWOP_LONGITUDE); if (sValue == NULL) { // we can't do without this! wvconfigExit (); radMsgLog (PRI_CATASTROPHIC, "%s failed!", configItemCWOP_LONGITUDE); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { wvstrncpy (cwopWork.longitude, sValue, sizeof(cwopWork.longitude)); } // get the WX packet logging preference iValue = wvconfigGetBooleanValue(configItemCWOP_LOG_WX_PACKET); if (iValue <= 0) { // just disable it cwopWork.logWXPackets = 0; } else { cwopWork.logWXPackets = iValue; } wvconfigExit (); if (statusInit(cwopWork.statusFile, cwopStatusLabels) == ERROR) { radMsgLog (PRI_HIGH, "statusInit failed - exiting..."); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } statusUpdate(STATUS_BOOTING); // wait a bit here before continuing radUtilsSleep (500); cwopWork.timer = radTimerCreate (NULL, timerHandler, NULL); if (cwopWork.timer == NULL) { statusUpdateMessage("radTimerCreate failed"); radMsgLog (PRI_HIGH, "radTimerCreate failed"); statusUpdate(STATUS_ERROR); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } radProcessTimerStart (cwopWork.timer, CWOP_MINUTE_INTERVAL); // register with the radlib message router if (radMsgRouterInit (WVIEW_RUN_DIR) == ERROR) { statusUpdateMessage("radMsgRouterInit failed"); radMsgLog (PRI_HIGH, "radMsgRouterInit failed!"); statusUpdate(STATUS_ERROR); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } // enable message reception from the radlib router for SHUTDOWN msgs radMsgRouterMessageRegister (WVIEW_MSG_TYPE_SHUTDOWN); // wait for the wview daemon to be ready if (waitForWviewDaemon () == ERROR) { radMsgLog (PRI_HIGH, "waitForWviewDaemon failed"); statusUpdate(STATUS_ERROR); radMsgRouterExit (); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } // enable message reception from the radlib router for archive notifications radMsgRouterMessageRegister (WVIEW_MSG_TYPE_ARCHIVE_NOTIFY); // enable message reception from the radlib router for POLL msgs radMsgRouterMessageRegister (WVIEW_MSG_TYPE_POLL); radMsgLog (PRI_STATUS, "CWOP: configured to submit station %s data to:", cwopWork.callSign); radMsgLog (PRI_STATUS, "CWOP: Primary: %s:%d", cwopWork.server1, cwopWork.portNo1); radMsgLog (PRI_STATUS, "CWOP: Secondary: %s:%d", cwopWork.server2, cwopWork.portNo2); radMsgLog (PRI_STATUS, "CWOP: Tertiary: %s:%d", cwopWork.server3, cwopWork.portNo3); radMsgLog (PRI_STATUS, "CWOP: Submitting every %d minutes at offset minute: %d", cwopWork.reportInterval, cwopWork.callSignOffset); // enter normal processing cwopWork.inMainLoop = TRUE; statusUpdate(STATUS_RUNNING); statusUpdateMessage("Normal operation"); radMsgLog (PRI_STATUS, "running..."); while (!cwopWork.exiting) { // wait on something interesting if (radProcessWait (0) == ERROR) { cwopWork.exiting = TRUE; } } statusUpdateMessage("exiting normally"); radMsgLog (PRI_STATUS, "exiting normally..."); statusUpdate(STATUS_SHUTDOWN); radMsgRouterExit (); radTimerDelete (cwopWork.timer); cwopSysExit (&cwopWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (0); }
static int waitForWviewDaemon (void) { WVIEW_MSG_REQUEST msg; char srcQName[QUEUE_NAME_LENGTH+1]; UINT msgType; UINT length; void *recvBfr; int retVal, done = FALSE; // enable message reception from the radlib router for the archive path radMsgRouterMessageRegister (WVIEW_MSG_TYPE_STATION_INFO); msg.requestType = WVIEW_RQST_TYPE_STATION_INFO; if (radMsgRouterMessageSend (WVIEW_MSG_TYPE_REQUEST, &msg, sizeof(msg)) == ERROR) { statusUpdateMessage("waitForWviewDaemon: radMsgRouterMessageSend failed!"); radMsgLog (PRI_HIGH, "waitForWviewDaemon: radMsgRouterMessageSend failed!"); radMsgRouterMessageDeregister (WVIEW_MSG_TYPE_STATION_INFO); return ERROR; } statusUpdate(STATUS_WAITING_FOR_WVIEW); // now wait for the response here while (!done) { radUtilsSleep (50); if ((retVal = radQueueRecv (radProcessQueueGetID (), srcQName, &msgType, &recvBfr, &length)) == FALSE) { continue; } else if (retVal == ERROR) { statusUpdateMessage("waitForWviewDaemon: queue is closed!"); radMsgLog (PRI_STATUS, "waitForWviewDaemon: queue is closed!"); radMsgRouterMessageDeregister (WVIEW_MSG_TYPE_STATION_INFO); return ERROR; } // is this what we want? if (msgType == WVIEW_MSG_TYPE_STATION_INFO) { // yes! done = TRUE; cwopWork.reportInterval = ((WVIEW_MSG_STATION_INFO*)recvBfr)->archiveInterval; if (cwopWork.reportInterval < 10) { cwopWork.reportInterval = 10; } } else if (msgType == WVIEW_MSG_TYPE_SHUTDOWN) { statusUpdateMessage("waitForWviewDaemon: received shutdown from wviewd"); radMsgLog (PRI_HIGH, "waitForWviewDaemon: received shutdown from wviewd"); radMsgRouterMessageDeregister (WVIEW_MSG_TYPE_STATION_INFO); return ERROR; } // release the received buffer radBufferRls (recvBfr); } // disable message reception from the radlib router for the archive path radMsgRouterMessageDeregister (WVIEW_MSG_TYPE_STATION_INFO); return OK; }
static void dumpConfig (void) { int numTries = 0; int channel; // initial wakeup of the VP console while ((vpifWakeupConsole (&wvWork) == ERROR) && (numTries < VPC_INITIAL_WAKEUP_TRIES)) { printf ("VP console WAKEUP failed - retry\n"); radUtilsSleep (1000); numTries ++; } if (numTries == VPC_INITIAL_WAKEUP_TRIES) { printf ("VP console WAKEUP failed - aborting\n"); return; } // get the archive interval if (vpconfigGetArchiveInterval (&wvWork) == ERROR) { printf ("vpconfigGetArchiveInterval failed - aborting\n"); return; } // get the RXCheck string if (vpifGetRXCheck (&wvWork) == ERROR) { printf ("vpifGetRXCheck failed - aborting\n"); return; } // get the version string if (vpconfigGetFWVersion (&wvWork) == ERROR) { printf ("vpconfigGetFWVersion failed - aborting\n"); return; } // get the Lat and Long if (vpifGetLatandLong (&wvWork) == ERROR) { printf ("vpifGetLatandLong failed - aborting\n"); return; } // get the Rain Season Start if (vpconfigGetRainSeasonStart (&wvWork) == ERROR) { printf ("vpconfigGetRainSeasonStart failed - aborting\n"); return; } // get the station wind direction calibration if (vpconfigGetWindDirectionCal (&wvWork) == ERROR) { printf ("vpconfigGetWindDirectionCal failed - aborting\n"); return; } // get the transmitter type and retransmitter settings if (vpconfigGetTransmitters (&wvWork) == ERROR) { printf ("vpconfigGetTransmitters failed - aborting\n"); return; } // get the rain collector size if (vpconfigGetRainCollectorSize (&wvWork) == ERROR) { printf ("vpconfigRainCollectorSize failed - aborting\n"); return; } // get the wind cup size if (vpconfigGetWindCupSize (&wvWork) == ERROR) { printf ("vpconfigGetWindCupSize failed - aborting\n"); return; } printf ("\n"); printf ("Firmware Version: %s\n", ((VP_IF_DATA *)wvWork.stationData)->fwVersion); printf ("Station Location: "); if (wvWork.latitude < 0) printf ("%.1f S, ", (float)(-wvWork.latitude)/10.0); else printf ("%.1f N, ", (float)wvWork.latitude/10.0); if (wvWork.longitude < 0) printf ("%.1f W, ", (float)(-wvWork.longitude)/10.0); else printf ("%.1f E, ", (float)wvWork.longitude/10.0); printf ("%d feet\n", (int)wvWork.elevation); printf ("Archive Interval: %d minutes\n", wvWork.archiveInterval); printf ("Rain Season Start Month: %d\n", ((VP_IF_DATA *)wvWork.stationData)->rainSeasonStart); printf ("Wind direction calibration: %d degrees\n", ((VP_IF_DATA *)wvWork.stationData)->windDirectionCal); for (channel = 0; channel < 8; channel++) { if (((VP_IF_DATA *)wvWork.stationData)->listenChannels & ((uint8_t) 1 << channel)) { uint8_t sensorType = ((VP_IF_DATA *)wvWork.stationData)->transmitterType[channel*2] & 0xF; uint8_t humidityIndex = (((VP_IF_DATA *)wvWork.stationData)->transmitterType[channel*2 + 1] & (uint8_t) 0xF0) >> 4; uint8_t temperatureIndex = ((VP_IF_DATA *)wvWork.stationData)->transmitterType[channel*2 + 1] & 0xF; printf ("Listening on channel: %d for ", channel + 1); switch ((VPRO_SENSOR_TYPES) sensorType) { case VPRO_SENSOR_ISS: printf("ISS\n"); break; case VPRO_SENSOR_TEMP: printf("temperature (ID %d)\n", temperatureIndex + 1); break; case VPRO_SENSOR_HUM: printf("humidity (ID %d)\n", humidityIndex); break; case VPRO_SENSOR_TEMP_HUM: printf("temperature (ID %d) and humidity (ID %d)\n", temperatureIndex + 1, humidityIndex); break; case VPRO_SENSOR_WIND: printf("wireless anemometer\n"); break; case VPRO_SENSOR_RAIN: printf("rain\n"); break; case VPRO_SENSOR_LEAF: printf("leaf wetness\n"); break; case VPRO_SENSOR_SOIL: printf("soil moisture\n"); break; case VPRO_SENSOR_LEAF_SOIL: printf("leaf wetness and soil moisture\n"); break; case VPRO_SENSOR_SENSORLINK: printf("SensorLink\n"); break; case VPRO_SENSOR_NONE: // Should not happen; tx bit in listenChannels should be off. printf("no sensor\n"); break; default: printf("unknown sensor type 0x%02x\n", sensorType); break; } } }
/* ... the main entry point for the alarm process */ int main (int argc, char *argv[]) { void (*alarmHandler)(int); int retVal; FILE *pidfile; WVIEW_ALARM *alarm; int runAsDaemon = TRUE; if (argc > 1) { if (!strcmp(argv[1], "-f")) { runAsDaemon = FALSE; } } memset (&alarmsWork, 0, sizeof (alarmsWork)); radListReset (&alarmsWork.alarmList); radListReset (&alarmsWork.clientList); /* ... initialize some system stuff first */ retVal = alarmsSysInit (&alarmsWork); if (retVal == ERROR) { radMsgLogInit (PROC_NAME_ALARMS, FALSE, TRUE); radMsgLog (PRI_CATASTROPHIC, "wvalarmd sysinit failed!"); radMsgLogExit (); exit (1); } else if (retVal == ERROR_ABORT) { exit (2); } /* ... call the global radlib system init function */ if (radSystemInit (WVIEW_SYSTEM_ID) == ERROR) { radMsgLogInit (PROC_NAME_ALARMS, TRUE, TRUE); radMsgLog (PRI_CATASTROPHIC, "radSystemInit failed!"); radMsgLogExit (); exit (1); } /* ... call the radlib process init function */ if (radProcessInit (PROC_NAME_ALARMS, alarmsWork.fifoFile, PROC_NUM_TIMERS_ALARMS, runAsDaemon, // TRUE for daemon msgHandler, evtHandler, NULL) == ERROR) { printf ("\nradProcessInit failed: %s\n\n", PROC_NAME_ALARMS); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } alarmsWork.myPid = getpid (); pidfile = fopen (alarmsWork.pidFile, "w"); if (pidfile == NULL) { radMsgLog (PRI_CATASTROPHIC, "lock file create failed!"); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } fprintf (pidfile, "%d", getpid ()); fclose (pidfile); alarmHandler = radProcessSignalGetHandler (SIGALRM); radProcessSignalCatchAll (defaultSigHandler); radProcessSignalCatch (SIGALRM, alarmHandler); radProcessSignalRelease(SIGABRT); // grab all of our alarm definitions from the config database retVal = readAlarmsConfig (); if (retVal == ERROR_ABORT) { radMsgLog (PRI_HIGH, "ALARM daemon not enabled - exiting..."); alarmsSysExit (&alarmsWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (0); } else if (retVal < 0) { radMsgLog (PRI_HIGH, "readAlarmsConfig failed - " "is there a problem with the wview config database?"); alarmsSysExit (&alarmsWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } else { radMsgLog (PRI_STATUS, "alarms: added %d alarm definitions", retVal); } if (statusInit(alarmsWork.statusFile, alarmsStatusLabels) == ERROR) { radMsgLog (PRI_HIGH, "ALARM status init failed - exiting..."); alarmsSysExit (&alarmsWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } statusUpdate(STATUS_BOOTING); statusUpdateStat(ALARM_STATS_ALARMS, retVal); // wait a bit here before continuing radUtilsSleep (500); // register with the radlib message router if (radMsgRouterInit (WVIEW_RUN_DIR) == ERROR) { statusUpdateMessage("radMsgRouterInit failed!"); radMsgLog (PRI_HIGH, "radMsgRouterInit failed!"); statusUpdate(STATUS_ERROR); alarmsSysExit (&alarmsWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } // enable message reception from the radlib router for SHUTDOWN msgs radMsgRouterMessageRegister (WVIEW_MSG_TYPE_SHUTDOWN); // wait for the wview daemon to be ready if (waitForWviewDaemon () == ERROR) { radMsgLog (PRI_HIGH, "waitForWviewDaemon failed"); statusUpdate(STATUS_ERROR); radMsgRouterExit (); alarmsSysExit (&alarmsWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } // finally, initialize our data feed socket alarmsWork.dataFeedServer = radSocketServerCreate(WV_DATAFEED_PORT); if (alarmsWork.dataFeedServer == NULL) { statusUpdateMessage("radSocketServerCreate failed"); radMsgLog (PRI_HIGH, "radSocketServerCreate failed..."); statusUpdate(STATUS_ERROR); radMsgRouterExit (); alarmsSysExit (&alarmsWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } // add it to our descriptors of interest if (radProcessIORegisterDescriptor(radSocketGetDescriptor(alarmsWork.dataFeedServer), dataFeedAccept, NULL) == ERROR) { statusUpdateMessage("radProcessIORegisterDescriptor server failed"); radMsgLog (PRI_HIGH, "radProcessIORegisterDescriptor failed..."); statusUpdate(STATUS_ERROR); radSocketDestroy (alarmsWork.dataFeedServer); radMsgRouterExit (); alarmsSysExit (&alarmsWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (1); } // enable message reception from the radlib router for loop data radMsgRouterMessageRegister (WVIEW_MSG_TYPE_LOOP_DATA_SVC); // enable message reception from the radlib router for archive data radMsgRouterMessageRegister (WVIEW_MSG_TYPE_ARCHIVE_DATA); // enable message reception from the radlib router for POLL msgs radMsgRouterMessageRegister (WVIEW_MSG_TYPE_POLL); // enter normal processing alarmsWork.inMainLoop = TRUE; statusUpdate(STATUS_RUNNING); statusUpdateMessage("Normal operation"); radMsgLog (PRI_STATUS, "running..."); // Do we need to trigger a test alarm? if (alarmsWork.doTest) { if (1 <= alarmsWork.doTestNumber && alarmsWork.doTestNumber <= ALARMS_MAX) { // Generate the bad boy: retVal = 1; for (alarm = (WVIEW_ALARM *) radListGetFirst (&alarmsWork.alarmList); retVal <= ALARMS_MAX && alarm != NULL; alarm = (WVIEW_ALARM *) radListGetNext (&alarmsWork.alarmList, (NODE_PTR)alarm)) { if (retVal == alarmsWork.doTestNumber) { // This is the one to test: alarm->triggerValue = -1; // run user script here if (executeScript(alarm) != 0) { radMsgLog (PRI_MEDIUM, "Test Alarm %d: script %s failed", retVal, alarm->scriptToRun); } else { radMsgLog (PRI_MEDIUM, "Test Alarm %d: script %s executed", retVal, alarm->scriptToRun); } retVal = ALARMS_MAX; } retVal ++; } } else { radMsgLog (PRI_MEDIUM, "Test Alarm: bad alarm index %d given!", alarmsWork.doTestNumber); } } while (!alarmsWork.exiting) { // wait on something interesting if (radProcessWait (0) == ERROR) { alarmsWork.exiting = TRUE; } } statusUpdateMessage("exiting normally"); radMsgLog (PRI_STATUS, "exiting normally..."); statusUpdate(STATUS_SHUTDOWN); radSocketDestroy (alarmsWork.dataFeedServer); radMsgRouterExit (); alarmsSysExit (&alarmsWork); radProcessExit (); radSystemExit (WVIEW_SYSTEM_ID); exit (0); }
int wh1080Init (WVIEWD_WORK *work) { WH1080_IF_DATA* ifWorkData = (WH1080_IF_DATA*)work->stationData; fd_set rfds; struct timeval tv; int ret; time_t nowTime = time(NULL) - (WV_SECONDS_IN_HOUR/(60/WH1080_RAIN_RATE_PERIOD)); ARCHIVE_PKT recordStore; unsigned char controlBlock[WH1080_BUFFER_CHUNK]; memset (&wh1080Work, 0, sizeof(wh1080Work)); // Create the rain accumulator (WH1080_RAIN_RATE_PERIOD minute age) // so we can compute rain rate: ifWorkData->rainRateAccumulator = sensorAccumInit(WH1080_RAIN_RATE_PERIOD); // Populate the accumulator with the last WH1080_RAIN_RATE_PERIOD minutes: while ((nowTime = dbsqliteArchiveGetNextRecord(nowTime, &recordStore)) != ERROR) { sensorAccumAddSample(ifWorkData->rainRateAccumulator, recordStore.dateTime, recordStore.value[DATA_INDEX_rain]); } if ((*(work->medium.usbhidInit))(&work->medium) != OK) { return ERROR; } // Set the station to log data once per minute: while ((!work->exiting) && (readFixedBlock(work, controlBlock) != OK)) { radMsgLog (PRI_HIGH, "WH1080: Initial fixed block read failed"); (*(work->medium.usbhidExit))(&work->medium); radUtilsSleep(5000); (*(work->medium.usbhidInit))(&work->medium); radMsgLog (PRI_HIGH, "WH1080: Retrying initial fixed block read"); } // For some reason the WH1080 wants the IF closed between a read and a write: (*(work->medium.usbhidExit))(&work->medium); if (work->exiting) { return ERROR; } controlBlock[WH1080_SAMPLING_INTERVAL] = 1; (*(work->medium.usbhidInit))(&work->medium); if (writeFixedBlock(work, controlBlock) == ERROR) { (*(work->medium.usbhidExit))(&work->medium); return ERROR; } radUtilsSleep(2000); (*(work->medium.usbhidExit))(&work->medium); radUtilsSleep(1000); wh1080Work.lastRecord = -1; // populate the LOOP structure: radMsgLog (PRI_HIGH, "Waiting for the next weather record to be ready " "in the console to populate initial wview sensor readings " "(this could take some time);"); radMsgLog (PRI_HIGH, "While waiting be sure you are receiving all sensors on the console;"); radMsgLog (PRI_HIGH, "if not, you may need to relocate the sensors or the console."); while ((!work->exiting) && (readStationData(work) != OK)) { radUtilsSleep(1000); } if (work->exiting) { return ERROR; } ifWorkData->wh1080Readings = wh1080Work.sensorData; storeLoopPkt (work, &work->loopPkt, &ifWorkData->wh1080Readings); // we must indicate successful completion here - // even though we are synchronous, the daemon wants to see this event: radProcessEventsSend (NULL, STATION_INIT_COMPLETE_EVENT, 0); return OK; }