// 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; }
static void drawGrid (MULTICHART_ID id) { register int i; int xlabelwidth = 0, ylabelwidth = 0; double units, step; double minR, stepR; int dataPoints, xnumhash, xhashindexlen; double hashwidth, xhashwidth; int numhash, x, y; char text[64][32], ylabelfmt[24]; char textR[64][32], ylabelfmtR[24]; // ... calculate the maximum number of hash marks and the units per hash // ... for the x-axis // build labels and calculate the maximum x-label width for (i = 0; i < id->numpoints; i ++) { if (strlen (id->pointnames[i]) > xlabelwidth) xlabelwidth = strlen (id->pointnames[i]); } xhashwidth = (xlabelwidth*gdFontSmall->h)/2; dataPoints = id->numpoints - 1; if (strlen (id->DualUnit) > 0) { // ((gdFontSmall->h/2) * strlen (id->DualUnit)))/2) - 2 id->imbx -= (gdFontMediumBold->h); if ((strcmp(id->DualUnit,"inches") == 0) || (strcmp(id->DualUnit,"knots") == 0) || (strcmp(id->DualUnit,"m/s") == 0)) id->imbx -= 7; } // see if a suggestion was given if (id->xnumhashes != 0) { xnumhash = id->xnumhashes; } else { xnumhash = (id->imbx - id->imtx)/xhashwidth; // try to normalize the number of hashmarks // try with the endpoint removed for (i = 1; i < dataPoints/2; i ++) { if (dataPoints % i != 0) continue; if (dataPoints/i <= xnumhash) { xnumhash = dataPoints/i; break; } } } xhashwidth = (double)(id->imbx - id->imtx)/(double)xnumhash; id->pointpixels = (double)(id->imbx - id->imtx)/(double)dataPoints; xhashindexlen = dataPoints/xnumhash; // ... calculate the maximum number of hash marks and the units per hash // ... for the y-axis hashwidth = (gdFontSmall->h * 3)/2; numhash = (id->imby - id->imty)/hashwidth; if (numhash > 64) numhash = 64; units = (id->max - id->min)/id->ystepSize; step = id->ystepSize; i = 0; while ((int)units > numhash && i < MAX_STEP_MULTIPLIER) { step = id->ystepSize * stepSizeMultipliers[i]; units = (id->max - id->min)/step; i ++; } id->ystepSize = step; numhash = (int)units; if ((id->min + (id->ystepSize * numhash)) < id->max) { numhash ++; } hashwidth = (double)(id->imby - id->imty)/(double)numhash; id->max = id->min + (id->ystepSize * numhash); id->ypixelconstant = (double)(id->imby - id->imty)/(double)(id->max - id->min); numhash ++; if (numhash > 64) numhash = 64; // build labels and calculate the maximum y-label width sprintf (ylabelfmt, "%%.%1.1df", id->ydecPlaces); for (i = 0; i < numhash; i ++) { sprintf (text[i], ylabelfmt, id->min + (i * id->ystepSize)); // now fill the right hand array with alternate scale @Rcm if (strlen(id->DualUnit) > 0) { textR[i][0] = ' '; if (strcmp(id->DualUnit,"C") == 0) { minR = wvutilsConvertFToC (id->min); stepR = ((id->ystepSize) * (5.0/9.0)); sprintf (textR[i], "%.1f", minR + (i * stepR)); } else if (strcmp(id->DualUnit,"F") == 0) { minR = wvutilsConvertCToF (id->min); stepR = ((id->ystepSize) * (9.0/5.0)); sprintf (textR[i], "%.1f", minR + (i * stepR)); } else if (strcmp(id->DualUnit,"mm") == 0) { minR = wvutilsConvertINToMM (id->min); stepR = wvutilsConvertINToMM (id->ystepSize); if (wvutilsConvertINToMM (id->max) >= 100) sprintf (textR[i], "%.0f", minR + (i * stepR)); else sprintf (textR[i], "%.1f", minR + (i * stepR)); } else if (strcmp(id->DualUnit,"inches") == 0) { minR = wvutilsConvertMMToIN (id->min); stepR = wvutilsConvertMMToIN (id->ystepSize); if (wvutilsConvertMMToIN (id->max) >= 100) sprintf (textR[i], "%.0f", minR + (i * stepR)); else sprintf (textR[i], "%.1f", minR + (i * stepR)); } else if (strcmp(id->DualUnit,"km/h") == 0) { minR = wvutilsConvertMilesToKilometers (id->min); stepR = wvutilsConvertMilesToKilometers (id->ystepSize); sprintf (textR[i], "%.0f", minR + (i * stepR)); } else if (strcmp(id->DualUnit,"mph") == 0) { minR = wvutilsConvertKilometersToMiles (id->min); stepR = wvutilsConvertKilometersToMiles (id->ystepSize); sprintf (textR[i], "%.0f", minR + (i * stepR)); } else if (strcmp(id->title,"m/s") == 0) { if (id->isMetric) { minR = wvutilsConvertMPSToKPH (id->min); stepR = wvutilsConvertMPSToKPH (id->ystepSize); sprintf (textR[i], "%.0f", minR + (i * stepR)); } else { minR = wvutilsConvertMPSToMPH (id->min); stepR = wvutilsConvertMPSToMPH (id->ystepSize); sprintf (textR[i], "%.0f", minR + (i * stepR)); } } else if (strcmp(id->title,"knots") == 0) { if (id->isMetric) { minR = wvutilsConvertKnotsToKPH (id->min); stepR = wvutilsConvertKnotsToKPH (id->ystepSize); sprintf (textR[i], "%.0f", minR + (i * stepR)); } else { minR = wvutilsConvertKnotsToMPH (id->min); stepR = wvutilsConvertKnotsToMPH (id->ystepSize); sprintf (textR[i], "%.0f", minR + (i * stepR)); } } else //all else: eg '%' or watts/m^2 (hum/ rad) { // same value both sides minR = id->min * 25.4; stepR = id->ystepSize * 25.4; sprintf (textR[i], "%s", text[i]); } if (strlen (text[i]) > ylabelwidth) ylabelwidth = strlen (text[i])+2; } else { if (strlen (text[i]) > ylabelwidth) ylabelwidth = strlen (text[i]); } } // ... now we know the chart area, draw it gdImageFilledRectangle (id->im, id->imtx - GLC_CONTENTS_OFFSET, id->imty - GLC_CONTENTS_OFFSET, id->imbx + GLC_CONTENTS_OFFSET, id->imby + GLC_CONTENTS_OFFSET, id->chartcolor); gdImageRectangle (id->im, id->imtx, id->imty, id->imbx, id->imby, id->gridcolor); // ... draw the y-axis gdImageSetThickness (id->im, 1); for (i = 0; i < numhash; i ++) { y = id->imby - (i * hashwidth); gdImageLine (id->im, id->imtx, y, id->imbx, y, id->gridcolor); y -= gdFontSmall->h/2; gdImageString (id->im, gdFontSmall, (id->imtx - 5) - (strlen(text[i]) * gdFontSmall->h/2), y, (UCHAR *)text[i], id->textcolor); if (strlen(id->DualUnit) > 0 ) { // right side x = id->imbx + (GLC_CONTENTS_OFFSET - 2); gdImageString (id->im, gdFontSmall, x + gdFontSmall->h/2, y, (UCHAR *)textR[i], id->textcolor); } } // ... draw the x-axis gdImageSetThickness (id->im, 1); for (i = 0; i <= xnumhash; i ++) // one more for right-most { int dataPoint = i * xhashindexlen; x = id->imtx + (i * xhashwidth); gdImageLine (id->im, x, id->imty, x, id->imby, id->gridcolor); if (strlen(id->pointnames[dataPoint]) < 2) x -= gdFontSmall->h/4; gdImageString (id->im, gdFontSmall, x - ((gdFontSmall->h/2) * (strlen(id->pointnames[dataPoint])/2)), (id->height - (3 * gdFontMediumBold->h)) + 4, (UCHAR *)id->pointnames[dataPoint], id->textcolor); } // ... finally, draw date gdImageString (id->im, gdFontSmall, ((id->width - ((gdFontSmall->h/2) * strlen (id->datetime)))/2) - 2, id->height - (gdFontMediumBold->h + 2), (UCHAR *)id->datetime, id->textcolor); }
// 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; }