// Returns: // OK - if new record retrieved // ERROR - if there was an interface error // ERROR_ABORT - if there is no new record (WH1080 generates new records at // best once a minute) static int readStationData (WVIEWD_WORK *work) { WH1080_IF_DATA* ifWorkData = (WH1080_IF_DATA*)work->stationData; int currentPosition, readPosition, index, retVal; if ((*(work->medium.usbhidInit))(&work->medium) != OK) { return ERROR; } // Read the WH1080 fixed block: retVal = readFixedBlock(work, &wh1080Work.controlBlock[0]); if (retVal == ERROR_ABORT) { // Try again later (bad magic number): (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } else if (retVal == ERROR) { // USB interface error: (*(work->medium.usbhidExit))(&work->medium); return ERROR; } // Get the current record position; the WH1080 reports the record it is // building, thus if it changes we need the prior just finished record: currentPosition = (int)getUSHORT(&wh1080Work.controlBlock[WH1080_CURRENT_POS]); // Make sure the index is aligned on 16-byte boundary: if ((currentPosition % 16) != 0) { // bogus, try again later: (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } // Is this the first time? if (wh1080Work.lastRecord == -1) { // Yes. wh1080Work.lastRecord = currentPosition; (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } // Is there a new record? if (currentPosition == wh1080Work.lastRecord) { // No, wait till it is finished. (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } // Read last record that is now complete: if (readBlock(work, wh1080Work.lastRecord, &wh1080Work.recordBlock[0]) == ERROR) { radMsgLog (PRI_HIGH, "WH1080: read data block at index %d failed!", wh1080Work.lastRecord); (*(work->medium.usbhidExit))(&work->medium); return ERROR; } (*(work->medium.usbhidExit))(&work->medium); readPosition = wh1080Work.lastRecord; wh1080Work.lastRecord = currentPosition; //radMsgLogData(wh1080Work.recordBlock, 32); // Is the record valid? Check for unpopulated record or no sensor data // received status bit: if ((wh1080Work.recordBlock[WH1080_STATUS] & 0x40) != 0) { // No! radMsgLog (PRI_HIGH, "WH1080: data block at index %d has bad status, ignoring the record", readPosition); return ERROR_ABORT; } // Parse the data received: for (index = 0; index < WH1080_NUM_SENSORS; index ++) { if (decodeSensor(&wh1080Work.recordBlock[decodeVals[index].pos], decodeVals[index].ws_type, decodeVals[index].scale, decodeVals[index].var) != OK) { // Bad sensor data, abort this cycle: radMsgLog (PRI_HIGH, "WH1080: data block at index %d has bad sensor value, ignoring the record", readPosition); return ERROR_ABORT; } } // Convert to Imperial units: wh1080Work.sensorData.intemp = wvutilsConvertCToF(wh1080Work.sensorData.intemp); wh1080Work.sensorData.outtemp = wvutilsConvertCToF(wh1080Work.sensorData.outtemp); wh1080Work.sensorData.pressure = wvutilsConvertHPAToINHG(wh1080Work.sensorData.pressure); wh1080Work.sensorData.windAvgSpeed = wvutilsConvertMPSToMPH(wh1080Work.sensorData.windAvgSpeed); wh1080Work.sensorData.windGustSpeed = wvutilsConvertMPSToMPH(wh1080Work.sensorData.windGustSpeed); wh1080Work.sensorData.rain = wvutilsConvertMMToIN(wh1080Work.sensorData.rain); 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; }
// Returns: // OK - if new record retrieved // ERROR - if there was an interface error // ERROR_ABORT - if there is no new record (WH1080 generates new records at // best once a minute) static int readStationData (WVIEWD_WORK *work) { WH1080_IF_DATA* ifWorkData = (WH1080_IF_DATA*)work->stationData; int currentPosition, index; if ((*(work->medium.usbhidInit))(&work->medium) != OK) { return ERROR; } // Read the WH1080 fixed block: if (readFixedBlock(work, &wh1080Work.controlBlock[0]) == ERROR) { (*(work->medium.usbhidExit))(&work->medium); return ERROR; } // Get the current record position; the WH1080 reports the record it is // building, thus if it changes we need the prior just finished record: currentPosition = (int)getUSHORT(&wh1080Work.controlBlock[WH1080_CURRENT_POS]); currentPosition -= WH1080_BUFFER_RECORD; if (currentPosition < WH1080_BUFFER_START) { // wrap back around to the end of the memory block: currentPosition = WH1080_BUFFER_END; } // Is there a new record? if (currentPosition == wh1080Work.lastRecord) { // No! (*(work->medium.usbhidExit))(&work->medium); return ERROR_ABORT; } // Read current and next record on first read on even position if (readBlock(work, currentPosition, &wh1080Work.recordBlock[0]) == ERROR) { radMsgLog (PRI_HIGH, "WH1080: read data block at index %d failed!", currentPosition); (*(work->medium.usbhidExit))(&work->medium); return ERROR; } (*(work->medium.usbhidExit))(&work->medium); wh1080Work.lastRecord = currentPosition; //radMsgLogData(wh1080Work.recordBlock, 32); // Is the record valid? Check for unpopulated record or no sensor data // received status bit: if (((wh1080Work.recordBlock[0] != 1)) || ((wh1080Work.recordBlock[WH1080_STATUS] & 0x40) != 0)) { // No! return ERROR_ABORT; } // Parse the data received: for (index = 0; index < WH1080_NUM_SENSORS; index ++) { if (decodeSensor(&wh1080Work.recordBlock[decodeVals[index].pos], decodeVals[index].ws_type, decodeVals[index].scale, decodeVals[index].var) != OK) { // Bad sensor data, abort this cycle: return ERROR_ABORT; } } // Convert to Imperial units: wh1080Work.sensorData.intemp = wvutilsConvertCToF(wh1080Work.sensorData.intemp); wh1080Work.sensorData.outtemp = wvutilsConvertCToF(wh1080Work.sensorData.outtemp); wh1080Work.sensorData.pressure = wvutilsConvertHPAToINHG(wh1080Work.sensorData.pressure); wh1080Work.sensorData.windAvgSpeed = wvutilsConvertMPSToMPH(wh1080Work.sensorData.windAvgSpeed); wh1080Work.sensorData.windGustSpeed = wvutilsConvertMPSToMPH(wh1080Work.sensorData.windGustSpeed); wh1080Work.sensorData.rain = wvutilsConvertMMToIN(wh1080Work.sensorData.rain); return OK; }