static void SendNextArchiveRecord(RADSOCK_ID client, ULONG dateTime) { ARCHIVE_PKT recordStore; ARCHIVE_PKT networkStore; WVIEW_ALARM_CLIENT* alarmClient; alarmClient = FindClient(client); if (alarmClient == NULL) { radMsgLog (PRI_HIGH, "SendNextArchiveRecord: failed to get client!"); return; } if (dbsqliteArchiveInit() == ERROR) { radMsgLog (PRI_HIGH, "SendNextArchiveRecord: failed to open archive db!"); return; } if (dbsqliteArchiveGetNextRecord((time_t)dateTime, &recordStore) == ERROR) { WriteArchiveToClient(client, NULL); alarmClient->syncInProgress = FALSE; return; } dbsqliteArchiveExit(); // Mark the sync in progress: alarmClient->syncInProgress = TRUE; // OK, send the bloody thing: datafeedConvertArchive_HTON(&networkStore, &recordStore); if (WriteArchiveToClient(client, &networkStore) == ERROR) { statusUpdateMessage("SendNextArchiveRecord: failed to write archive record!"); radMsgLog (PRI_HIGH, "SendNextArchiveRecord: failed to write archive record!"); return; } return; }
int wmr918Init (WVIEWD_WORK *work) { WMR918_IF_DATA* ifWorkData = (WMR918_IF_DATA*)work->stationData; fd_set rfds; struct timeval tv; int i, length, retVal; time_t nowTime = time(NULL) - (WV_SECONDS_IN_HOUR/(60/WMR918_RAIN_RATE_PERIOD)); ARCHIVE_PKT recordStore; char outString[128]; memset (&wmr918Work, 0, sizeof(wmr918Work)); // Create the rain accumulator (WMR918_RAIN_RATE_PERIOD minute age) // so we can compute rain rate: ifWorkData->rainRateAccumulator = sensorAccumInit(WMR918_RAIN_RATE_PERIOD); // Populate the accumulator with the last WMR918_RAIN_RATE_PERIOD minutes: while ((nowTime = dbsqliteArchiveGetNextRecord(nowTime, &recordStore)) != ERROR) { sensorAccumAddSample(ifWorkData->rainRateAccumulator, recordStore.dateTime, recordStore.value[DATA_INDEX_rain]); } radMsgLog (PRI_MEDIUM, "wmr918Init: waiting for first sensor packets (this may take some time):"); while ((wmr918Work.dataRXMask != WMR918_SENSOR_ALL) && (! work->exiting)) { // Log what we are waiting for: length = 0; for (i = 0; i < 4; i ++) { if (! (wmr918Work.dataRXMask & (1 << i))) { length += sprintf(&outString[length], "%s ", WMRSensorNames[i]); } } radMsgLog (PRI_MEDIUM, "wmr918Init: waiting for sensors: %s", outString); tv.tv_sec = 2; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(work->medium.fd, &rfds); if (select (work->medium.fd + 1, &rfds, NULL, NULL, &tv) > 0) { retVal = readStationData (work); switch (retVal) { case WMR918GROUP0: radMsgLog (PRI_MEDIUM, "received WIND packet..."); break; case WMR918GROUP1: radMsgLog (PRI_MEDIUM, "received RAIN packet..."); break; case WMR918GROUP2: radMsgLog (PRI_MEDIUM, "received EXTRA TEMP packet..."); break; case WMR918GROUP3: radMsgLog (PRI_MEDIUM, "received OUT TEMP packet..."); break; case WMR918GROUP4: radMsgLog (PRI_MEDIUM, "received POOL TEMP packet..."); break; case WMR918GROUP5: case WMR918GROUP6: radMsgLog (PRI_MEDIUM, "received IN TEMP packet..."); break; default: break; } } } if (! work->exiting) { radMsgLog (PRI_MEDIUM, "wmr918Init: first sensor packets received."); } // populate the LOOP structure: ifWorkData->wmr918Readings = wmr918Work.sensorData; storeLoopPkt (work, &work->loopPkt, &ifWorkData->wmr918Readings); // 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; }
// station-supplied init function // -- Can Be Asynchronous - event indication required -- // // MUST: // - set the 'stationGeneratesArchives' flag in WVIEWD_WORK: // if the station generates archive records (TRUE) or they should be // generated automatically by the daemon from the sensor readings (FALSE) // - Initialize the 'stationData' store for station work area // - Initialize the interface medium // - do initial LOOP acquisition // - do any catch-up on archive records if there is a data logger // - 'work->runningFlag' can be used for start up synchronization but should // not be modified by the station interface code // - indicate init is done by sending the STATION_INIT_COMPLETE_EVENT event to // this process (radProcessEventsSend (NULL, STATION_INIT_COMPLETE_EVENT, 0)) // // OPTIONAL: // - Initialize a state machine or any other construct required for the // station interface - these should be stored in the 'stationData' store // // 'archiveIndication' - indication callback used to pass back an archive record // generated as a result of 'stationGetArchive' being called; should receive a // NULL pointer for 'newRecord' if no record available; only used if // 'stationGeneratesArchives' flag is set to TRUE by the station interface // // Returns: OK or ERROR // int stationInit ( WVIEWD_WORK *work, void (*archiveIndication)(ARCHIVE_PKT* newRecord) ) { int i; ARCHIVE_PKT recordStore; time_t nowTime; memset (&twiWorkData, 0, sizeof(twiWorkData)); pwviewWork = work; twiWorkData.baudrate = B19200; // save the archive indication callback (we should never need it) ArchiveIndicator = archiveIndication; // set our work data pointer work->stationData = &twiWorkData; // set the Archive Generation flag to indicate the TWI DOES NOT // generate them work->stationGeneratesArchives = FALSE; // initialize the medium abstraction based on user configuration if (!strcmp (work->stationInterface, "serial")) { if (serialMediumInit (&work->medium, serialPortConfig, O_RDWR | O_NOCTTY | O_NDELAY) == ERROR) { radMsgLog (PRI_HIGH, "stationInit: serial MediumInit failed"); return ERROR; } } else if (!strcmp (work->stationInterface, "ethernet")) { if (ethernetMediumInit (&work->medium, work->stationHost, work->stationPort) == ERROR) { radMsgLog (PRI_HIGH, "stationInit: ethernet MediumInit failed"); return ERROR; } } else { radMsgLog (PRI_HIGH, "stationInit: medium %s not supported", work->stationInterface); return ERROR; } // initialize the interface using the media specific routine if ((*(work->medium.init)) (&work->medium, work->stationDevice) == ERROR) { radMsgLog (PRI_HIGH, "stationInit: medium setup failed"); return ERROR; } // Autobaud the station now: twiWorkData.baudrate = twiConfig(work); if (twiWorkData.baudrate <= 0) { radMsgLog (PRI_HIGH, "TWI: twiProtocolInit: autobaud failed!"); return ERROR; } radMsgLog (PRI_STATUS, "TWI: autobaud = %d", twiWorkData.baudrate); // Reconfigure the serial port here to ensure consistency: serialPortConfig(work->medium.fd); tcflush (work->medium.fd, TCIFLUSH); tcflush (work->medium.fd, TCOFLUSH); if (!strcmp (work->stationInterface, "serial")) { radMsgLog (PRI_STATUS, "TWI on %s opened ...", work->stationDevice); } else if (!strcmp (work->stationInterface, "ethernet")) { radMsgLog (PRI_STATUS, "TWI on %s:%d opened ...", work->stationHost, work->stationPort); } // grab the station configuration now if (stationGetConfigValueInt (work, STATION_PARM_ELEVATION, &twiWorkData.elevation) == ERROR) { radMsgLog (PRI_HIGH, "stationInit: stationGetConfigValueInt ELEV failed!"); (*(work->medium.exit)) (&work->medium); return ERROR; } if (stationGetConfigValueFloat (work, STATION_PARM_LATITUDE, &twiWorkData.latitude) == ERROR) { radMsgLog (PRI_HIGH, "stationInit: stationGetConfigValueInt LAT failed!"); (*(work->medium.exit)) (&work->medium); return ERROR; } if (stationGetConfigValueFloat (work, STATION_PARM_LONGITUDE, &twiWorkData.longitude) == ERROR) { radMsgLog (PRI_HIGH, "stationInit: stationGetConfigValueInt LONG failed!"); (*(work->medium.exit)) (&work->medium); return ERROR; } if (stationGetConfigValueInt (work, STATION_PARM_ARC_INTERVAL, &twiWorkData.archiveInterval) == ERROR) { radMsgLog (PRI_HIGH, "stationInit: stationGetConfigValueInt ARCINT failed!"); (*(work->medium.exit)) (&work->medium); return ERROR; } // set the work archive interval now work->archiveInterval = twiWorkData.archiveInterval; // sanity check the archive interval against the most recent record if (stationVerifyArchiveInterval (work) == ERROR) { // bad magic! radMsgLog (PRI_HIGH, "stationInit: stationVerifyArchiveInterval failed!"); radMsgLog (PRI_HIGH, "You must either move old archive data out of the way -or-"); radMsgLog (PRI_HIGH, "fix the interval setting..."); (*(work->medium.exit)) (&work->medium); return ERROR; } else { radMsgLog (PRI_STATUS, "station archive interval: %d minutes", work->archiveInterval); } twiWorkData.totalRain = 0; // Create the rain accumulator (TWI_RAIN_RATE_PERIOD minute age) // so we can compute rain rate: twiWorkData.rainRateAccumulator = sensorAccumInit(TWI_RAIN_RATE_PERIOD); // Populate the accumulator with the last TWI_RAIN_RATE_PERIOD minutes: nowTime = time(NULL) - (WV_SECONDS_IN_HOUR/(60/TWI_RAIN_RATE_PERIOD)); while ((nowTime = dbsqliteArchiveGetNextRecord(nowTime, &recordStore)) != ERROR) { sensorAccumAddSample(twiWorkData.rainRateAccumulator, recordStore.dateTime, recordStore.value[DATA_INDEX_rain]); } radMsgLog (PRI_STATUS, "Starting station interface: TWI"); // initialize the station interface if (twiProtocolInit(work) == ERROR) { radMsgLog (PRI_HIGH, "stationInit: twiProtocolInit failed!"); (*(work->medium.exit)) (&work->medium); return ERROR; } // do the initial GetReadings now if (twiProtocolGetReadings(work, &twiWorkData.twiReadings) != OK) { radMsgLog (PRI_HIGH, "stationInit: initial twiProtocolGetReadings failed!"); twiProtocolExit (work); (*(work->medium.exit)) (&work->medium); return ERROR; } // Initialize the 12-hour temp accumulator: twi12HourTempAvg = sensorAccumInit(60 * 12); // Load data for the last 12 hours: nowTime = time(NULL) - (WV_SECONDS_IN_HOUR * 12); while ((nowTime = dbsqliteArchiveGetNextRecord(nowTime, &recordStore)) != ERROR) { sensorAccumAddSample(twi12HourTempAvg, recordStore.dateTime, recordStore.value[DATA_INDEX_outTemp]); } // populate the LOOP structure storeLoopPkt (work, &work->loopPkt, &twiWorkData.twiReadings); // 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; }
// initialize the computed values from the archive records int computedDataInit (WVIEWD_WORK *work) { time_t lastArchiveTime, firstArchiveTime, nowtime = time(NULL); struct tm bknnowtime; int rainyear; ARCHIVE_PKT recordStore; localtime_r(&nowtime, &bknnowtime); rainyear = bknnowtime.tm_year + 1900; if (work->stationRainSeasonStart > (bknnowtime.tm_mon + 1)) { // we need to go back a year... rainyear --; } radMsgLog (PRI_STATUS, "initializing computed data values..."); memset (&cdWork, 0, sizeof (cdWork)); // initialize the stores: windAverageReset (&work->sensors.wind[STF_ALL]); windAverageReset (&work->sensors.wind[STF_YEAR]); windAverageReset (&work->sensors.wind[STF_MONTH]); windAverageReset (&work->sensors.wind[STF_WEEK]); windAverageReset (&work->sensors.wind[STF_DAY]); windAverageReset (&work->sensors.wind[STF_HOUR]); sensorClearSet (work->sensors.sensor[STF_ALL]); sensorClearSet (work->sensors.sensor[STF_YEAR]); sensorClearSet (work->sensors.sensor[STF_MONTH]); sensorClearSet (work->sensors.sensor[STF_WEEK]); sensorClearSet (work->sensors.sensor[STF_DAY]); sensorClearSet (work->sensors.sensor[STF_HOUR]); lastArchiveTime = 0; firstArchiveTime = dbsqliteArchiveGetNextRecord(0, &recordStore); // Only compute if there are archive records: if ((int)firstArchiveTime != ERROR) { // update ALL data types to get started (ignore failures) computeDataAllTime(work, firstArchiveTime); computeDataYear(work, lastArchiveTime); // Add in any preset values if the year is right: if (work->stationRainETPresetYear == rainyear) { sensorAddCumulative (&work->sensors.sensor[STF_YEAR][SENSOR_RAIN], work->stationRainYTDPreset); sensorAddCumulative (&work->sensors.sensor[STF_YEAR][SENSOR_ET], work->stationETYTDPreset); } computeDataMonth (work, lastArchiveTime); computeDataWeek (work, lastArchiveTime); computeDataDay (work, lastArchiveTime); computeDataHour (work, lastArchiveTime); } sensorClearSet (work->sensors.sensor[STF_INTERVAL]); // initialize per-interval housekeeping intervalHousekeepingInit (work); // save the current time so we will know when things need to be updated nowtime -= (work->archiveInterval * 60); localtime_r (&nowtime, &bknnowtime); cdWork.currentHour = bknnowtime.tm_hour; cdWork.currentDay = bknnowtime.tm_mday; cdWork.currentMonth = bknnowtime.tm_mon; cdWork.currentYear = bknnowtime.tm_year; return OK; }
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; }